-> Custom Properties for Mesh entities
authorGeoffrey Bantle <hairbat@yahoo.com>
Mon, 4 Jun 2007 19:18:19 +0000 (19:18 +0000)
committerGeoffrey Bantle <hairbat@yahoo.com>
Mon, 4 Jun 2007 19:18:19 +0000 (19:18 +0000)
In order to give import/export script authors the ability to add properties
to inidividual faces, vertices and edges in the same manner as they are able
to do with ID structures three new custom data types have been added to blender
for floats, integers and strings.

Things to note:

-Since property Layers are custom data, they are added to all verts, edges
 or faces at once.
-Only one property layer for each unique property name may exist. In  other
 words, you cannot have a float layer as well as an integer layer
 both with the same name.
-No user interface for this exists at the moment.

The following methods and attributes have been added to the Blender.Mesh
Python module and it's object types:

->MVert/Edge/FaceSeq:
addPropertyLayer(name, type)
removePropertyLayer(name)
renamePropertyLayer(original name, new name)
properties(readonly list.)

->MVert/Edge/Face
getProperty(name)
setProperty(name, value)

->Mesh module
PropertyTypes (readonly dictionary)

source/blender/blenkernel/intern/customdata.c
source/blender/blenlib/BLI_editVert.h
source/blender/makesdna/DNA_customdata_types.h
source/blender/makesdna/DNA_meshdata_types.h
source/blender/python/api2_2x/Mesh.c
source/blender/src/editmesh.c

index e239583c4eb13e66337eaa4874381502623400ab..2c8199f90f361722d82e6fc669e61dbdb76c0cf7 100644 (file)
@@ -367,20 +367,24 @@ const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
        /* 3 floats per normal vector */
        {sizeof(float)*3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
        {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+       {sizeof(MFloatProperty), "MFloatProperty",1,"Float",NULL,NULL,NULL,NULL},
+       {sizeof(MIntProperty), "MIntProperty",1,"Int",NULL,NULL,NULL,NULL},
+       {sizeof(MStringProperty), "MStringProperty",1,"String",NULL,NULL,NULL,NULL},
 };
 
 const char *LAYERTYPENAMES[CD_NUMTYPES] = {
        "CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace", "CDMTFace",
-       "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags"};
+       "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags","CDMFloatProperty","CDMIntProperty","CDMStringProperty"};
 
 const CustomDataMask CD_MASK_BAREMESH =
        CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE;
 const CustomDataMask CD_MASK_MESH =
        CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE |
-       CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MCOL;
+       CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MCOL |
+       CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR;
 const CustomDataMask CD_MASK_EDITMESH =
        CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
-       CD_MASK_MCOL;
+       CD_MASK_MCOL|CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR;
 const CustomDataMask CD_MASK_DERIVEDMESH =
        CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
        CD_MASK_MCOL | CD_MASK_ORIGINDEX;
@@ -1335,6 +1339,13 @@ const char *CustomData_layertype_name(int type)
        return layerType_getName(type);
 }
 
+static int  CustomData_is_property_layer(int type)
+{
+       if((type == CD_PROP_FLT) || (type == CD_PROP_INT) || (type == CD_PROP_STR))
+               return 1;
+       return 0;
+}
+
 void CustomData_set_layer_unique_name(CustomData *data, int index)
 {
        char tempname[64];
@@ -1355,9 +1366,17 @@ void CustomData_set_layer_unique_name(CustomData *data, int index)
        /* see if there is a duplicate */
        for(i=0; i<data->totlayer; i++) {
                layer = &data->layers[i];
-
-               if(i!=index && layer->type==type && strcmp(layer->name, name)==0)
-                       break;
+               
+               if(CustomData_is_property_layer(type)){
+                       if(i!=index && CustomData_is_property_layer(layer->type) && 
+                               strcmp(layer->name, name)==0)
+                                       break;  
+               
+               }
+               else{
+                       if(i!=index && layer->type==type && strcmp(layer->name, name)==0)
+                               break;
+               }
        }
 
        if(i == data->totlayer)
@@ -1373,8 +1392,16 @@ void CustomData_set_layer_unique_name(CustomData *data, int index)
                for(i=0; i<data->totlayer; i++) {
                        layer = &data->layers[i];
                        
-                       if(i!=index && layer->type==type && strcmp(layer->name, tempname)==0)
+                       if(CustomData_is_property_layer(type)){
+                               if(i!=index && CustomData_is_property_layer(layer->type) && 
+                                       strcmp(layer->name, tempname)==0)
+
                                break;
+                       }
+                       else{
+                               if(i!=index && layer->type==type && strcmp(layer->name, tempname)==0)
+                                       break;
+                       }
                }
 
                if(i == data->totlayer) {
index a763ad53f1f904a21b8c0efb7e1c1b70481cac30..c05d33f2792c783a13dae01e4efb3f8f5a3548c8 100644 (file)
@@ -106,6 +106,7 @@ typedef struct EditEdge
        short fast;             /* only 0 or 1, for editmesh_fastmalloc */
        short fgoni;            /* index for fgon, for search */
        HashEdge hash;
+       void *data;                     /*custom edge data*/
 } EditEdge;
 
 /* note; changing this also might affect the undo copy in editmesh.c */
@@ -171,7 +172,7 @@ typedef struct EditMesh
 
        struct RetopoPaintData *retopo_paint_data;
 
-       CustomData vdata, fdata;
+       CustomData vdata, edata, fdata;
 
 #ifdef WITH_VERSE
        void *vnode;
index b9f6ab0e60b70091d3adecbf2bd6453b13ef1490..1c1676ba2770a028bf943e9e0123375fc76ae485 100644 (file)
@@ -64,7 +64,10 @@ typedef struct CustomData {
 #define CD_ORIGINDEX   7
 #define CD_NORMAL              8
 #define CD_FLAGS               9
-#define CD_NUMTYPES            10
+#define CD_PROP_FLT            10
+#define CD_PROP_INT            11
+#define CD_PROP_STR            12
+#define CD_NUMTYPES            13
 
 /* Bits for CustomDataMask */
 #define CD_MASK_MVERT          (1 << CD_MVERT)
@@ -77,6 +80,10 @@ typedef struct CustomData {
 #define CD_MASK_ORIGINDEX      (1 << CD_ORIGINDEX)
 #define CD_MASK_NORMAL         (1 << CD_NORMAL)
 #define CD_MASK_FLAGS          (1 << CD_FLAGS)
+#define CD_MASK_PROP_FLT       (1 << CD_PROP_FLT)
+#define CD_MASK_PROP_INT       (1 << CD_PROP_INT)
+#define CD_MASK_PROP_STR       (1 << CD_PROP_STR)
+
 
 /* CustomData.flag */
 
index af9c1ae629df6973942715973dd82281be14677f..b2aecc57269d62c4b94446b39aea91b091a68dce 100644 (file)
@@ -86,6 +86,18 @@ typedef struct MTFace {
        short mode, tile, unwrap;
 } MTFace;
 
+/*Custom Data Properties*/
+typedef struct MFloatProperty{
+       float   f;
+} MFloatProperty;
+typedef struct MIntProperty{
+       int             i;
+} MIntProperty;
+typedef struct MStringProperty{
+       char    s[256];
+} MStringProperty;
+
+
 /* Multiresolution modeling */
 typedef struct MultiresCol {
        float a, r, g, b;
index bd78900f625abd849c6fe5bf49c2cb2110d55e7f..bd79c2878d90547584ac2aaf819a0a6aa2ce3a66 100644 (file)
@@ -1226,6 +1226,239 @@ static long MVert_hash( BPy_MVert *self )
        return (long)self->index;
 }
 
+static PyObject *Mesh_addPropLayer_internal(Mesh *mesh, CustomData *data, int tot, PyObject *args)
+{
+       char *name=NULL;
+       int type = -1;
+       
+       if( !PyArg_ParseTuple( args, "si", &name, &type) )
+               return EXPP_ReturnPyObjError( PyExc_TypeError,
+                                                       "expected a string and an int" );
+       if (strlen(name)>31)
+               return EXPP_ReturnPyObjError( PyExc_ValueError,
+                                                       "error, maximum name length is 31");
+       if((type != CD_PROP_FLT) && (type != CD_PROP_INT) && (type != CD_PROP_STR))
+               return EXPP_ReturnPyObjError( PyExc_ValueError,
+                                                       "error, unknown layer type");
+       if (name)
+               CustomData_add_layer_named(data, type, CD_DEFAULT, NULL,tot,name);
+       
+       mesh_update_customdata_pointers(mesh);
+       Py_RETURN_NONE;
+}
+
+static PyObject *Mesh_removePropLayer_internal(Mesh *mesh, CustomData *data, int tot,PyObject *args)
+{
+       CustomDataLayer *layer;
+       char *name=NULL;
+       int i;
+       
+       if( !PyArg_ParseTuple( args, "s", &name ) )
+               return EXPP_ReturnPyObjError( PyExc_TypeError,
+                                             "expected string argument" );
+       
+       if (strlen(name)>31)
+               return EXPP_ReturnPyObjError( PyExc_ValueError,
+                               "error, maximum name length is 31" );
+       
+       i = CustomData_get_named_layer_index(data, CD_PROP_FLT, name);
+       if(i == -1) i = CustomData_get_named_layer_index(data, CD_PROP_INT, name);
+       if(i == -1) i = CustomData_get_named_layer_index(data, CD_PROP_STR, name);
+       if (i==-1)
+               return EXPP_ReturnPyObjError(PyExc_ValueError,
+                       "No matching layers to remove" );       
+       layer = &data->layers[i];
+       CustomData_free_layer(data, layer->type, tot, i);
+       mesh_update_customdata_pointers(mesh);
+
+       Py_RETURN_NONE;
+}
+
+static PyObject *Mesh_renamePropLayer_internal(Mesh *mesh, CustomData *data, PyObject *args)
+{
+       CustomDataLayer *layer;
+       int i;
+       char *name_from, *name_to;
+       
+       if( !PyArg_ParseTuple( args, "ss", &name_from, &name_to ) )
+               return EXPP_ReturnPyObjError( PyExc_TypeError,
+                               "expected 2 strings" );
+       
+       if (strlen(name_from)>31 || strlen(name_to)>31)
+               return EXPP_ReturnPyObjError( PyExc_ValueError,
+                               "error, maximum name length is 31" );
+       
+       i = CustomData_get_named_layer_index(data, CD_PROP_FLT, name_from);
+       if(i == -1) i = CustomData_get_named_layer_index(data, CD_PROP_INT, name_from);
+       if(i == -1) i = CustomData_get_named_layer_index(data, CD_PROP_STR, name_from);
+       if(i == -1)
+               return EXPP_ReturnPyObjError(PyExc_ValueError,
+                       "No matching layers to rename" );       
+
+       layer = &data->layers[i];
+       
+       strcpy(layer->name, name_to); /* we alredy know the string sizes are under 32 */
+       CustomData_set_layer_unique_name(data, i);
+       Py_RETURN_NONE;
+}
+
+static PyObject *Mesh_propList_internal(CustomData *data)
+{
+       CustomDataLayer *layer;
+       PyObject *list = PyList_New( 0 ), *item;
+       int i;
+       for(i=0; i<data->totlayer; i++) {
+               layer = &data->layers[i];
+               if( (layer->type == CD_PROP_FLT) || (layer->type == CD_PROP_INT) || (layer->type == CD_PROP_STR)) {
+                       item = PyString_FromString(layer->name);
+                       PyList_Append( list, item );
+                       Py_DECREF(item);
+               }
+       }
+       return list;
+} 
+
+static PyObject *Mesh_getProperty_internal(CustomData *data, int eindex, PyObject *args)
+{
+       CustomDataLayer *layer;
+       char *name=NULL;
+       int i;
+       MFloatProperty *pf;
+       MIntProperty *pi;
+       MStringProperty *ps;
+
+       if(!PyArg_ParseTuple(args, "s", &name))
+               return EXPP_ReturnPyObjError( PyExc_TypeError,
+                       "expected an string argument" );
+       
+       if (strlen(name)>31)
+               return EXPP_ReturnPyObjError( PyExc_ValueError,
+                               "error, maximum name length is 31" );
+       
+       i = CustomData_get_named_layer_index(data, CD_PROP_FLT, name);
+       if(i == -1) i = CustomData_get_named_layer_index(data, CD_PROP_INT, name);
+       if(i == -1) i = CustomData_get_named_layer_index(data, CD_PROP_STR, name);
+       if(i == -1)
+               return EXPP_ReturnPyObjError(PyExc_ValueError,
+                       "No matching layers" ); 
+       
+       layer = &data->layers[i];
+
+       if(layer->type == CD_PROP_FLT){ 
+               pf = layer->data;
+               return PyFloat_FromDouble(pf[eindex].f);
+       }
+       else if(layer->type == CD_PROP_INT){
+               pi = layer->data;
+               return PyInt_FromLong(pi[eindex].i);
+       
+       }
+       else if(layer->type == CD_PROP_STR){
+               ps = layer->data;
+               return PyString_FromString(ps[eindex].s);
+       }
+       Py_RETURN_NONE;
+}
+
+static PyObject *Mesh_setProperty_internal(CustomData *data, int eindex, PyObject *args)
+{
+       CustomDataLayer *layer;
+       int i,index, type = -1;
+       float f;
+       char *s=NULL, *name=NULL;
+       MFloatProperty *pf;
+       MIntProperty  *pi;
+       MStringProperty *ps;
+       PyObject *val;
+       
+       if(PyArg_ParseTuple(args, "sO", &name, &val)){
+               if (strlen(name)>31)
+                       return EXPP_ReturnPyObjError( PyExc_ValueError,
+                                       "error, maximum name length is 31" );
+               
+               if(PyInt_CheckExact(val)){ 
+                       type = CD_PROP_INT;
+                       i = (int)PyInt_AS_LONG(val);
+               }
+               else if(PyFloat_CheckExact(val)){
+                       type = CD_PROP_FLT;
+                       f = (float)PyFloat_AsDouble(val);
+               }
+               else if(PyString_CheckExact(val)){
+                       type = CD_PROP_STR;
+                       s = PyString_AsString(val);
+               }
+               else
+                       return EXPP_ReturnPyObjError( PyExc_TypeError,
+                                       "expected an name plus either float/int/string" );
+
+       }
+
+       index = CustomData_get_named_layer_index(data, type, name);
+       if(index == -1)
+               return EXPP_ReturnPyObjError(PyExc_ValueError,
+                       "No matching layers or type mismatch" );        
+
+       layer = &data->layers[index];
+       
+       if(type==CD_PROP_STR){
+               if (strlen(s)>255){
+                       return EXPP_ReturnPyObjError( PyExc_ValueError,
+                               "error, maximum string length is 255");
+               }
+               else{
+                       ps =  layer->data;
+                       strcpy(ps[eindex].s,s);
+               }
+       }
+       else if(type==CD_PROP_FLT){
+               pf = layer->data;
+               pf[eindex].f = f;
+       }
+       else{
+               pi = layer->data;
+               pi[eindex].i = i;
+       }
+       Py_RETURN_NONE;
+}
+
+static PyObject *MVert_getProp( BPy_MVert *self, PyObject *args)
+{
+       if( BPy_MVert_Check( self ) ){
+               Mesh *me = (Mesh *)self->data;
+               if(self->index >= me->totvert)
+                       return EXPP_ReturnPyObjError( PyExc_ValueError,
+                               "error, MVert is no longer valid part of mesh!");
+               else
+                       return Mesh_getProperty_internal(&(me->vdata), self->index, args);
+       }
+       return EXPP_ReturnPyObjError( PyExc_ValueError,
+                               "error, Vertex not part of a mesh!");
+}
+
+static PyObject *MVert_setProp( BPy_MVert *self,  PyObject *args)
+{
+       if( BPy_MVert_Check( self ) ){
+               Mesh *me = (Mesh *)self->data;
+               if(self->index >= me->totvert)
+                       return EXPP_ReturnPyObjError( PyExc_ValueError,
+                               "error, MVert is no longer valid part of mesh!");
+               else
+                       return Mesh_setProperty_internal(&(me->vdata), self->index, args);
+       }
+       return EXPP_ReturnPyObjError( PyExc_ValueError,
+                               "error, Vertex not part of a mesh!");
+}
+       
+static struct PyMethodDef BPy_MVert_methods[] = {
+       {"getProperty", (PyCFunction)MVert_getProp, METH_VARARGS,
+               "get property indicated by name"},
+       {"setProperty", (PyCFunction)MVert_setProp, METH_VARARGS,
+               "set property indicated by name"},
+       {NULL, NULL, 0, NULL}
+};
+
+
 /************************************************************************
  *
  * Python MVert_Type structure definition
@@ -1290,7 +1523,7 @@ PyTypeObject MVert_Type = {
        NULL,                       /* iternextfunc tp_iternext; */
 
   /*** Attribute descriptor and subclassing stuff ***/
-       NULL,                       /* struct PyMethodDef *tp_methods; */
+       BPy_MVert_methods,          /* struct PyMethodDef *tp_methods; */
        NULL,                       /* struct PyMemberDef *tp_members; */
        BPy_MVert_getseters,        /* struct PyGetSetDef *tp_getset; */
        NULL,                       /* struct _typeobject *tp_base; */
@@ -1955,6 +2188,37 @@ static PyObject *MVertSeq_selected( BPy_MVertSeq * self )
        }
        return list;
 }
+static PyObject *MVertSeq_add_layertype(BPy_MVertSeq *self, PyObject *args)
+{
+       Mesh *me = (Mesh*)self->mesh;
+       return Mesh_addPropLayer_internal(me, &(me->vdata), me->totvert, args);
+}
+static PyObject *MVertSeq_del_layertype(BPy_MVertSeq *self, PyObject *args)
+{
+       Mesh *me = (Mesh*)self->mesh;
+       return Mesh_removePropLayer_internal(me, &(me->vdata), me->totvert, args);
+}
+static PyObject *MVertSeq_rename_layertype(BPy_MVertSeq *self, PyObject *args)
+{
+       Mesh *me = (Mesh*)self->mesh;
+       return Mesh_renamePropLayer_internal(me,&(me->vdata),args);
+}
+static PyObject *MVertSeq_PropertyList(BPy_MVertSeq *self) 
+{
+       Mesh *me = (Mesh*)self->mesh;
+       return Mesh_propList_internal(&(me->vdata));
+}
+static PyObject *M_Mesh_PropertiesTypeDict(void)
+{
+       PyObject *Types = PyConstant_New( );
+       if(Types) {
+               BPy_constant *d = (BPy_constant *) Types;
+               PyConstant_Insert(d, "FLOAT", PyInt_FromLong(CD_PROP_FLT));
+               PyConstant_Insert(d, "INT" , PyInt_FromLong(CD_PROP_INT));
+               PyConstant_Insert(d, "STRING", PyInt_FromLong(CD_PROP_STR));
+       }
+       return Types;
+}
 
 static struct PyMethodDef BPy_MVertSeq_methods[] = {
        {"extend", (PyCFunction)MVertSeq_extend, METH_VARARGS,
@@ -1963,9 +2227,25 @@ static struct PyMethodDef BPy_MVertSeq_methods[] = {
                "delete vertices from mesh"},
        {"selected", (PyCFunction)MVertSeq_selected, METH_NOARGS,
                "returns a list containing indices of selected vertices"},
+       {"addPropertyLayer",(PyCFunction)MVertSeq_add_layertype, METH_VARARGS,
+               "add a new property layer"},
+       {"removePropertyLayer",(PyCFunction)MVertSeq_del_layertype, METH_VARARGS,
+               "removes a property layer"},
+       {"renamePropertyLayer",(PyCFunction)MVertSeq_rename_layertype, METH_VARARGS,
+               "renames an existing property layer"},
        {NULL, NULL, 0, NULL}
 };
 
+static PyGetSetDef BPy_MVertSeq_getseters[] = {
+       {"properties",
+       (getter)MVertSeq_PropertyList, (setter)NULL,
+       "vertex property layers, read only",
+       NULL},
+       {NULL,NULL,NULL,NULL,NULL}  /* Sentinel */
+};
+
+
+
 /************************************************************************
  *
  * Python MVertSeq_Type standard operations
@@ -2035,7 +2315,7 @@ PyTypeObject MVertSeq_Type = {
   /*** Attribute descriptor and subclassing stuff ***/
        BPy_MVertSeq_methods,       /* struct PyMethodDef *tp_methods; */
        NULL,                       /* struct PyMemberDef *tp_members; */
-       NULL,                       /* struct PyGetSetDef *tp_getset; */
+       BPy_MVertSeq_getseters,     /* struct PyGetSetDef *tp_getset; */
        NULL,                       /* struct _typeobject *tp_base; */
        NULL,                       /* PyObject *tp_dict; */
        NULL,                       /* descrgetfunc tp_descr_get; */
@@ -2452,7 +2732,25 @@ static long MEdge_hash( BPy_MEdge *self )
 {
        return (long)self->index;
 }
+static PyObject *MEdge_getProp( BPy_MEdge *self, PyObject *args)
+{
+       Mesh *me = (Mesh *)self->mesh;
+       return Mesh_getProperty_internal(&(me->edata), self->index, args);
+}
+
+static PyObject *MEdge_setProp( BPy_MEdge *self,  PyObject *args)
+{
+       Mesh *me = (Mesh *)self->mesh;
+       return Mesh_setProperty_internal(&(me->edata), self->index, args);
+}
 
+static struct PyMethodDef BPy_MEdge_methods[] = {
+       {"getProperty", (PyCFunction)MEdge_getProp, METH_VARARGS,
+               "get property indicated by name"},
+       {"setProperty", (PyCFunction)MEdge_setProp, METH_VARARGS,
+               "set property indicated by name"},
+       {NULL, NULL, 0, NULL}
+};
 /************************************************************************
  *
  * Python MEdge_Type structure definition
@@ -2517,7 +2815,7 @@ PyTypeObject MEdge_Type = {
        ( iternextfunc ) MEdge_nextIter, /* iternextfunc tp_iternext; */
 
   /*** Attribute descriptor and subclassing stuff ***/
-       NULL,                       /* struct PyMethodDef *tp_methods; */
+       BPy_MEdge_methods,          /* struct PyMethodDef *tp_methods; */
        NULL,                       /* struct PyMemberDef *tp_members; */
        BPy_MEdge_getseters,        /* struct PyGetSetDef *tp_getset; */
        NULL,                       /* struct _typeobject *tp_base; */
@@ -3311,6 +3609,28 @@ static PyObject *MEdgeSeq_selected( BPy_MEdgeSeq * self )
        return list;
 }
 
+static PyObject *MEdgeSeq_add_layertype(BPy_MEdgeSeq *self, PyObject *args)
+{
+       Mesh *me = (Mesh*)self->mesh;
+       return Mesh_addPropLayer_internal(me, &(me->edata), me->totedge, args);
+}
+static PyObject *MEdgeSeq_del_layertype(BPy_MEdgeSeq *self, PyObject *args)
+{
+       Mesh *me = (Mesh*)self->mesh;
+       return Mesh_removePropLayer_internal(me, &(me->edata), me->totedge, args);
+}
+static PyObject *MEdgeSeq_rename_layertype(BPy_MEdgeSeq *self, PyObject *args)
+{
+       Mesh *me = (Mesh*)self->mesh;
+       return Mesh_renamePropLayer_internal(me,&(me->edata),args);
+}
+static PyObject *MEdgeSeq_PropertyList(BPy_MEdgeSeq *self) 
+{
+       Mesh *me = (Mesh*)self->mesh;
+       return Mesh_propList_internal(&(me->edata));
+}
+
+
 static struct PyMethodDef BPy_MEdgeSeq_methods[] = {
        {"extend", (PyCFunction)MEdgeSeq_extend, METH_VARARGS,
                "add edges to mesh"},
@@ -3320,8 +3640,23 @@ static struct PyMethodDef BPy_MEdgeSeq_methods[] = {
                "returns a list containing indices of selected edges"},
        {"collapse", (PyCFunction)MEdgeSeq_collapse, METH_VARARGS,
                "collapse one or more edges to a vertex"},
+       {"addPropertyLayer",(PyCFunction)MEdgeSeq_add_layertype, METH_VARARGS,
+               "add a new property layer"},
+       {"removePropertyLayer",(PyCFunction)MEdgeSeq_del_layertype, METH_VARARGS,
+               "removes a property layer"},
+       {"renamePropertyLayer",(PyCFunction)MEdgeSeq_rename_layertype, METH_VARARGS,
+               "renames an existing property layer"},
+
        {NULL, NULL, 0, NULL}
 };
+static PyGetSetDef BPy_MEdgeSeq_getseters[] = {
+       {"properties",
+       (getter)MEdgeSeq_PropertyList, (setter)NULL,
+       "edge property layers, read only",
+       NULL},
+       {NULL,NULL,NULL,NULL,NULL}  /* Sentinel */
+};
+
 
 /************************************************************************
  *
@@ -3392,7 +3727,7 @@ PyTypeObject MEdgeSeq_Type = {
   /*** Attribute descriptor and subclassing stuff ***/
        BPy_MEdgeSeq_methods,       /* struct PyMethodDef *tp_methods; */
        NULL,                       /* struct PyMemberDef *tp_members; */
-       NULL,                       /* struct PyGetSetDef *tp_getset; */
+       BPy_MEdgeSeq_getseters,     /* struct PyGetSetDef *tp_getset; */
        NULL,                       /* struct _typeobject *tp_base; */
        NULL,                       /* PyObject *tp_dict; */
        NULL,                       /* descrgetfunc tp_descr_get; */
@@ -4469,6 +4804,35 @@ static PySequenceMethods MFace_as_sequence = {
        0,0,0,
 };
 
+static PyObject *MFace_getProp( BPy_MFace *self, PyObject *args)
+{
+       Mesh *me = (Mesh *)self->mesh;
+       MFace *face = MFace_get_pointer( self );
+       if( !face )
+               return NULL;
+       mesh_update_customdata_pointers(me); //!
+       return Mesh_getProperty_internal(&(me->fdata), self->index, args);
+}
+
+static PyObject *MFace_setProp( BPy_MFace *self,  PyObject *args)
+{
+       Mesh *me = (Mesh *)self->mesh;
+       PyObject *obj;
+       MFace *face = MFace_get_pointer( self );
+       if( !face )
+               return NULL;
+       obj = Mesh_setProperty_internal(&(me->fdata), self->index, args);
+       mesh_update_customdata_pointers(me); //!
+       return obj;
+}
+
+static struct PyMethodDef BPy_MFace_methods[] = {
+       {"getProperty", (PyCFunction)MFace_getProp, METH_VARARGS,
+               "get property indicated by name"},
+       {"setProperty", (PyCFunction)MFace_setProp, METH_VARARGS,
+               "set property indicated by name"},
+       {NULL, NULL, 0, NULL}
+};
 /************************************************************************
  *
  * Python MFace_Type structure definition
@@ -4533,7 +4897,7 @@ PyTypeObject MFace_Type = {
        ( iternextfunc ) MFace_nextIter, /* iternextfunc tp_iternext; */
 
   /*** Attribute descriptor and subclassing stuff ***/
-       NULL,                       /* struct PyMethodDef *tp_methods; */
+       BPy_MFace_methods,          /* struct PyMethodDef *tp_methods; */
        NULL,                       /* struct PyMemberDef *tp_members; */
        BPy_MFace_getseters,        /* struct PyGetSetDef *tp_getset; */
        NULL,                       /* struct _typeobject *tp_base; */
@@ -5242,6 +5606,27 @@ static PyObject *MFaceSeq_selected( BPy_MFaceSeq * self )
        return list;
 }
 
+static PyObject *MFaceSeq_add_layertype(BPy_MFaceSeq *self, PyObject *args)
+{
+       Mesh *me = (Mesh*)self->mesh;
+       return Mesh_addPropLayer_internal(me, &(me->fdata), me->totface, args);
+}
+static PyObject *MFaceSeq_del_layertype(BPy_MFaceSeq *self, PyObject *args)
+{
+       Mesh *me = (Mesh*)self->mesh;
+       return Mesh_removePropLayer_internal(me, &(me->fdata), me->totface, args);
+}
+static PyObject *MFaceSeq_rename_layertype(BPy_MFaceSeq *self, PyObject *args)
+{
+       Mesh *me = (Mesh*)self->mesh;
+       return Mesh_renamePropLayer_internal(me,&(me->fdata),args);
+}
+static PyObject *MFaceSeq_PropertyList(BPy_MFaceSeq *self) 
+{
+       Mesh *me = (Mesh*)self->mesh;
+       return Mesh_propList_internal(&(me->fdata));
+}
+
 static struct PyMethodDef BPy_MFaceSeq_methods[] = {
        {"extend", (PyCFunction)MFaceSeq_extend, METH_VARARGS|METH_KEYWORDS,
                "add faces to mesh"},
@@ -5249,8 +5634,22 @@ static struct PyMethodDef BPy_MFaceSeq_methods[] = {
                "delete faces from mesh"},
        {"selected", (PyCFunction)MFaceSeq_selected, METH_NOARGS,
                "returns a list containing indices of selected faces"},
+       {"addPropertyLayer",(PyCFunction)MFaceSeq_add_layertype, METH_VARARGS,
+               "add a new property layer"},
+       {"removePropertyLayer",(PyCFunction)MFaceSeq_del_layertype, METH_VARARGS,
+               "removes a property layer"},
+       {"renamePropertyLayer",(PyCFunction)MFaceSeq_rename_layertype, METH_VARARGS,
+               "renames an existing property layer"},
        {NULL, NULL, 0, NULL}
 };
+static PyGetSetDef BPy_MFaceSeq_getseters[] = {
+       {"properties",
+       (getter)MFaceSeq_PropertyList, (setter)NULL,
+       "vertex property layers, read only",
+       NULL},
+       {NULL,NULL,NULL,NULL,NULL}  /* Sentinel */
+};
+
 
 /************************************************************************
  *
@@ -5321,7 +5720,7 @@ PyTypeObject MFaceSeq_Type = {
   /*** Attribute descriptor and subclassing stuff ***/
        BPy_MFaceSeq_methods,       /* struct PyMethodDef *tp_methods; */
        NULL,                       /* struct PyMemberDef *tp_members; */
-       NULL,                       /* struct PyGetSetDef *tp_getset; */
+       BPy_MFaceSeq_getseters,     /* struct PyGetSetDef *tp_getset; */
        NULL,                       /* struct _typeobject *tp_base; */
        NULL,                       /* PyObject *tp_dict; */
        NULL,                       /* descrgetfunc tp_descr_get; */
@@ -8156,7 +8555,8 @@ PyObject *Mesh_Init( void )
        PyObject *EdgeFlags = M_Mesh_EdgeFlagsDict(  );
        PyObject *AssignModes = M_Mesh_VertAssignDict( );
        PyObject *SelectModes = M_Mesh_SelectModeDict( );
-
+       PyObject *PropertyTypes = M_Mesh_PropertiesTypeDict( );
+       
        if( PyType_Ready( &MCol_Type ) < 0 )
                return NULL;
        if( PyType_Ready( &MVert_Type ) < 0 )
@@ -8196,6 +8596,9 @@ PyObject *Mesh_Init( void )
                PyModule_AddObject( submodule, "AssignModes", AssignModes );
        if( SelectModes )
                PyModule_AddObject( submodule, "SelectModes", SelectModes );
+       if( PropertyTypes )
+               PyModule_AddObject( submodule, "PropertyTypes", PropertyTypes );
+
 
 
        return submodule;
index 9b0811bf788aef70c9e6f1391baa88d2d2bdb9b8..fe6708f5959ee3ba14f8de9a41eaee1c981d964c 100644 (file)
@@ -859,6 +859,7 @@ void make_editMesh()
        else {
                MEdge *medge= me->medge;
                
+               CustomData_copy(&me->edata, &em->edata, CD_MASK_EDITMESH, CD_CALLOC, 0);
                /* make edges */
                for(a=0; a<me->totedge; a++, medge++) {
                        eed= addedgelist(evlist[medge->v1], evlist[medge->v2], NULL);
@@ -873,6 +874,7 @@ void make_editMesh()
                                if(medge->flag & ME_HIDE) eed->h |= 1;
                                if(G.scene->selectmode==SCE_SELECT_EDGE) 
                                        EM_select_edge(eed, eed->f & SELECT);           // force edge selection to vertices, seems to be needed ...
+                               CustomData_to_em_block(&me->edata,&em->edata, a, &eed->data);
                        }
                }
                
@@ -1014,6 +1016,7 @@ void load_editMesh(void)
        me->totface= G.totface;
 
        CustomData_copy(&em->vdata, &me->vdata, CD_MASK_MESH, CD_CALLOC, me->totvert);
+       CustomData_copy(&em->edata, &me->edata, CD_MASK_MESH, CD_CALLOC, me->totedge);
        CustomData_copy(&em->fdata, &me->fdata, CD_MASK_MESH, CD_CALLOC, me->totface);
 
        CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert);
@@ -1071,7 +1074,8 @@ void load_editMesh(void)
                if(eed->h & 1) medge->flag |= ME_HIDE;
                
                medge->crease= (char)(255.0*eed->crease);
-               
+               CustomData_from_em_block(&em->edata, &me->edata, eed->data, a);         
+
                eed->tmp.l = a++;
                
                medge++;
@@ -1823,7 +1827,7 @@ typedef struct UndoMesh {
        short selectmode;
        RetopoPaintData *retopo_paint_data;
        char retopo_mode;
-       CustomData vdata, fdata;
+       CustomData vdata, edata, fdata;
        EM_MultiresUndo *mru;
 } UndoMesh;
 
@@ -1839,6 +1843,7 @@ static void free_undoMesh(void *umv)
        if(um->selected) MEM_freeN(um->selected);
        if(um->retopo_paint_data) retopo_free_paint_data(um->retopo_paint_data);
        CustomData_free(&um->vdata, um->totvert);
+       CustomData_free(&um->edata, um->totedge);
        CustomData_free(&um->fdata, um->totface);
        if(um->mru) {
                --um->mru->users;
@@ -1881,6 +1886,7 @@ static void *editMesh_to_undoMesh(void)
        if(um->totsel) esec= um->selected= MEM_callocN(um->totsel*sizeof(EditSelectionC), "allselections");
 
        if(um->totvert) CustomData_copy(&em->vdata, &um->vdata, CD_MASK_EDITMESH, CD_CALLOC, um->totvert);
+       if(um->totedge) CustomData_copy(&em->edata, &um->edata, CD_MASK_EDITMESH, CD_CALLOC, um->totedge);
        if(um->totface) CustomData_copy(&em->fdata, &um->fdata, CD_MASK_EDITMESH, CD_CALLOC, um->totface);
        
        /* now copy vertices */
@@ -1909,6 +1915,8 @@ static void *editMesh_to_undoMesh(void)
                eedc->crease= (short)(eed->crease*255.0);
                eedc->fgoni= eed->fgoni;
                eed->tmp.l = a; /*store index*/
+               CustomData_from_em_block(&em->edata, &um->edata, eed->data, a);
+       
        }
        
        /* copy faces */
@@ -2000,9 +2008,11 @@ static void undoMesh_to_editMesh(void *umv)
 #endif
 
        CustomData_free(&em->vdata, 0);
+       CustomData_free(&em->edata, 0);
        CustomData_free(&em->fdata, 0);
 
        CustomData_copy(&um->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
+       CustomData_copy(&um->edata, &em->edata, CD_MASK_EDITMESH, CD_CALLOC, 0);
        CustomData_copy(&um->fdata, &em->fdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
 
        /* now copy vertices */
@@ -2030,6 +2040,7 @@ static void undoMesh_to_editMesh(void *umv)
                eed->sharp= eedc->sharp;
                eed->fgoni= eedc->fgoni;
                eed->crease= ((float)eedc->crease)/255.0;
+               CustomData_to_em_block(&um->edata, &em->edata, a, &eed->data);
        }
        
        /* copy faces */