merge with trunk at r27259 and commit of a patch by anthony jones to fix msvc (though...
[blender-staging.git] / source / blender / blenkernel / intern / customdata.c
index 34ad666029460d48d2542c8727da6e04c11437a7..f2d9512ce18376fd03cf381912c694c0ea573815 100644 (file)
@@ -34,6 +34,7 @@
 
 #include <math.h>
 #include <string.h>
+#include "BLI_cellalloc.h"
 
 #include "MEM_guardedalloc.h"
 
 #include "BKE_global.h"
 #include "BKE_utildefines.h"
 
+#include "bmesh.h"
+
+#include <math.h>
+#include <string.h>
+
 /* number of layers to add when growing a CustomData object */
 #define CUSTOMDATA_GROW 5
 
@@ -95,6 +101,14 @@ typedef struct LayerTypeInfo {
           default is assumed to be all zeros */
        void (*set_default)(void *data, int count);
 
+    /* functions necassary for geometry collapse*/
+       int (*equal)(void *data1, void *data2);
+       void (*multiply)(void *data, float fac);
+       void (*initminmax)(void *min, void *max);
+       void (*add)(void *data1, void *data2);
+       void (*dominmax)(void *data1, void *min, void *max);
+       void (*copyvalue)(void *source, void *dest);
+
     /* a function to read data from a cdf file */
        int (*read)(CDataFile *cdf, void *data, int count);
 
@@ -116,7 +130,7 @@ static void layerCopy_mdeformvert(const void *source, void *dest,
                MDeformVert *dvert = (MDeformVert *)((char *)dest + i * size);
 
                if(dvert->totweight) {
-                       MDeformWeight *dw = MEM_callocN(dvert->totweight * sizeof(*dw),
+                       MDeformWeight *dw = BLI_cellalloc_calloc(dvert->totweight * sizeof(*dw),
                                                                                        "layerCopy_mdeformvert dw");
 
                        memcpy(dw, dvert->dw, dvert->totweight * sizeof(*dw));
@@ -135,7 +149,7 @@ static void layerFree_mdeformvert(void *data, int count, int size)
                MDeformVert *dvert = (MDeformVert *)((char *)data + i * size);
 
                if(dvert->dw) {
-                       MEM_freeN(dvert->dw);
+                       BLI_cellalloc_free(dvert->dw);
                        dvert->dw = NULL;
                        dvert->totweight = 0;
                }
@@ -144,7 +158,7 @@ static void layerFree_mdeformvert(void *data, int count, int size)
 
 static void linklist_free_simple(void *link)
 {
-       MEM_freeN(link);
+       BLI_cellalloc_free(link);
 }
 
 static void layerInterp_mdeformvert(void **sources, float *weights,
@@ -177,7 +191,7 @@ static void layerInterp_mdeformvert(void **sources, float *weights,
 
                        /* if this def_nr is not in the list, add it */
                        if(!node) {
-                               MDeformWeight *tmp_dw = MEM_callocN(sizeof(*tmp_dw),
+                               MDeformWeight *tmp_dw = BLI_cellalloc_calloc(sizeof(*tmp_dw),
                                                            "layerInterp_mdeformvert tmp_dw");
                                tmp_dw->def_nr = dw->def_nr;
                                tmp_dw->weight = dw->weight * interp_weight;
@@ -188,10 +202,10 @@ static void layerInterp_mdeformvert(void **sources, float *weights,
        }
 
        /* now we know how many unique deform weights there are, so realloc */
-       if(dvert->dw) MEM_freeN(dvert->dw);
+       if(dvert->dw) BLI_cellalloc_free(dvert->dw);
 
        if(totweight) {
-               dvert->dw = MEM_callocN(sizeof(*dvert->dw) * totweight,
+               dvert->dw = BLI_cellalloc_calloc(sizeof(*dvert->dw) * totweight,
                                        "layerInterp_mdeformvert dvert->dw");
                dvert->totweight = totweight;
 
@@ -271,6 +285,7 @@ static void layerInterp_tface(void **sources, float *weights,
        }
 
        *tf = *(MTFace *)sources[0];
+
        for(j = 0; j < 4; ++j) {
                tf->uv[j][0] = uv[j][0];
                tf->uv[j][1] = uv[j][1];
@@ -599,12 +614,86 @@ static size_t layerFilesize_mdisps(CDataFile *cdf, void *data, int count)
 }
 
 /* --------- */
+static void layerCopyValue_mloopcol(void *source, void *dest)
+{
+       MLoopCol *m1 = source, *m2 = dest;
+       
+       m2->r = m1->r;
+       m2->g = m1->g;
+       m2->b = m1->b;
+       m2->a = m1->a;
+}
+
+static int layerEqual_mloopcol(void *data1, void *data2)
+{
+       MLoopCol *m1 = data1, *m2 = data2;
+       float r, g, b, a;
+
+       r = m1->r - m2->r;
+       g = m1->g - m2->g;
+       b = m1->b - m2->b;
+       a = m1->a - m2->a;
+
+       return r*r + g*g + b*b + a*a < 0.001;
+}
+
+static void layerMultiply_mloopcol(void *data, float fac)
+{
+       MLoopCol *m = data;
+
+       m->r = (float)m->r * fac;
+       m->g = (float)m->g * fac;
+       m->b = (float)m->b * fac;
+       m->a = (float)m->a * fac;
+}
+
+static void layerAdd_mloopcol(void *data1, void *data2)
+{
+       MLoopCol *m = data1, *m2 = data2;
+
+       m->r += m2->r;
+       m->g += m2->g;
+       m->b += m2->b;
+       m->a += m2->a;
+}
+
+static void layerDoMinMax_mloopcol(void *data, void *vmin, void *vmax)
+{
+       MLoopCol *m = data;
+       MLoopCol *min = vmin, *max = vmax;
+
+       if (m->r < min->r) min->r = m->r;
+       if (m->g < min->g) min->g = m->g;
+       if (m->b < min->b) min->b = m->b;
+       if (m->a < min->a) min->a = m->a;
+       
+       if (m->r > max->r) max->r = m->r;
+       if (m->g > max->g) max->g = m->g;
+       if (m->b > max->b) max->b = m->b;
+       if (m->a > max->a) max->a = m->a;
+}
+
+static void layerInitMinMax_mloopcol(void *vmin, void *vmax)
+{
+       MLoopCol *min = vmin, *max = vmax;
+
+       min->r = 255;
+       min->g = 255;
+       min->b = 255;
+       min->a = 255;
+
+       max->r = 0;
+       max->g = 0;
+       max->b = 0;
+       max->a = 0;
+}
 
 static void layerDefault_mloopcol(void *data, int count)
 {
-       static MLoopCol default_mloopcol = {255,255,255,255};
+       MLoopCol default_mloopcol = {255,255,255,255};
        MLoopCol *mlcol = (MLoopCol*)data;
        int i;
+
        for(i = 0; i < count; i++)
                mlcol[i] = default_mloopcol;
 
@@ -654,6 +743,56 @@ static void layerInterp_mloopcol(void **sources, float *weights,
        mc->g = (int)col.g;
        mc->b = (int)col.b;
 }
+
+static void layerCopyValue_mloopuv(void *source, void *dest)
+{
+       MLoopUV *luv1 = source, *luv2 = dest;
+       
+       luv2->uv[0] = luv1->uv[0];
+       luv2->uv[1] = luv1->uv[1];
+}
+
+static int layerEqual_mloopuv(void *data1, void *data2)
+{
+       MLoopUV *luv1 = data1, *luv2 = data2;
+       float u, v;
+
+       u = luv1->uv[0] - luv2->uv[0];
+       v = luv1->uv[1] - luv2->uv[1];
+
+       return u*u + v*v < 0.00001;
+}
+
+static void layerMultiply_mloopuv(void *data, float fac)
+{
+       MLoopUV *luv = data;
+
+       luv->uv[0] *= fac;
+       luv->uv[1] *= fac;
+}
+
+static void layerInitMinMax_mloopuv(void *vmin, void *vmax)
+{
+       MLoopUV *min = vmin, *max = vmax;
+
+       INIT_MINMAX2(min->uv, max->uv);
+}
+
+static void layerDoMinMax_mloopuv(void *data, void *vmin, void *vmax)
+{
+       MLoopUV *min = vmin, *max = vmax, *luv = data;
+
+       DO_MINMAX2(luv->uv, min->uv, max->uv);
+}
+
+static void layerAdd_mloopuv(void *data1, void *data2)
+{
+       MLoopUV *l1 = data1, *l2 = data2;
+
+       l1->uv[0] += l2->uv[0];
+       l1->uv[1] += l2->uv[1];
+}
+
 static void layerInterp_mloopuv(void **sources, float *weights,
                                float *sub_weights, int count, void *dest)
 {
@@ -761,7 +900,26 @@ static void layerDefault_mcol(void *data, int count)
                mcol[i] = default_mcol;
 }
 
+static void layerInterp_shapekey(void **sources, float *weights,
+                             float *sub_weights, int count, void *dest)
+{
+       float *co = dest, *src;
+       float **in = sources;
+       int i, j, k;
 
+       if(count <= 0) return;
+
+       memset(co, 0, sizeof(float)*3);
+       
+       for(i = 0; i < count; ++i) {
+               float weight = weights ? weights[i] : 1.0f;
+               
+               src = in[i];
+               co[0] += src[0] * weight;
+               co[1] += src[1] * weight;
+               co[2] += src[2] * weight;
+       }
+}
 
 const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
        {sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL},
@@ -787,45 +945,65 @@ const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
         layerInterp_origspace_face, layerSwap_origspace_face, layerDefault_origspace_face},
        {sizeof(float)*3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
        {sizeof(MTexPoly), "MTexPoly", 1, "Face Texture", NULL, NULL, NULL, NULL, NULL},
-       {sizeof(MLoopUV), "MLoopUV", 1, "UV coord", NULL, NULL, layerInterp_mloopuv, NULL, NULL},
-       {sizeof(MLoopCol), "MLoopCol", 1, "Col", NULL, NULL, layerInterp_mloopcol, NULL, layerDefault_mloopcol},
+       {sizeof(MLoopUV), "MLoopUV", 1, "UV coord", NULL, NULL, layerInterp_mloopuv, NULL, NULL,
+        layerEqual_mloopuv, layerMultiply_mloopuv, layerInitMinMax_mloopuv, 
+        layerAdd_mloopuv, layerDoMinMax_mloopuv, layerCopyValue_mloopuv},
+       {sizeof(MLoopCol), "MLoopCol", 1, "Col", NULL, NULL, layerInterp_mloopcol, NULL, 
+        layerDefault_mloopcol, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol, 
+        layerAdd_mloopcol, layerDoMinMax_mloopcol, layerCopyValue_mloopcol},
        {sizeof(float)*3*4, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
        {sizeof(MDisps), "MDisps", 1, NULL, layerCopy_mdisps,
-        layerFree_mdisps, layerInterp_mdisps, layerSwap_mdisps, NULL, layerRead_mdisps, layerWrite_mdisps, layerFilesize_mdisps},
+        layerFree_mdisps, layerInterp_mdisps, layerSwap_mdisps, NULL, 
+        NULL, NULL, NULL, NULL, NULL, NULL, 
+        layerRead_mdisps, layerWrite_mdisps, layerFilesize_mdisps},
        {sizeof(MCol)*4, "MCol", 4, "WeightCol", NULL, NULL, layerInterp_mcol,
         layerSwap_mcol, layerDefault_mcol},
-        {sizeof(MCol)*4, "MCol", 4, "IDCol", NULL, NULL, layerInterp_mcol,
+       {sizeof(MPoly), "MPoly", 1, "NGon Face", NULL, NULL, NULL, NULL, NULL},
+       {sizeof(MLoop), "MLoop", 1, "NGon Face-Vertex", NULL, NULL, NULL, NULL, NULL},
+       {sizeof(MLoopCol), "MLoopCol", 1, "WeightLoopCol", NULL, NULL, layerInterp_mloopcol, NULL, 
+        layerDefault_mloopcol, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol, 
+        layerAdd_mloopcol, layerDoMinMax_mloopcol, layerCopyValue_mloopcol},
+       {sizeof(MCol)*4, "MCol", 4, "IDCol", NULL, NULL, layerInterp_mcol,
         layerSwap_mcol, layerDefault_mcol},
-        {sizeof(MCol)*4, "MCol", 4, "TexturedCol", NULL, NULL, layerInterp_mcol,
+       {sizeof(MCol)*4, "MCol", 4, "TextureCol", NULL, NULL, layerInterp_mcol,
         layerSwap_mcol, layerDefault_mcol},
+       {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+       {sizeof(float)*3, "", 0, "ShapeKey", NULL, NULL, layerInterp_shapekey},
 };
 
 const char *LAYERTYPENAMES[CD_NUMTYPES] = {
        "CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace", "CDMTFace",
        "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags","CDMFloatProperty",
        "CDMIntProperty","CDMStringProperty", "CDOrigSpace", "CDOrco", "CDMTexPoly", "CDMLoopUV",
-       "CDMloopCol", "CDTangent", "CDMDisps", "CDWeightMCol"};
+       "CDMloopCol", "CDTangent", "CDMDisps", "CDWeightMCol", "CDMPoly", 
+       "CDMLoop", "CDMLoopCol", "CDIDCol", "CDTextureCol", "CDShapeKeyIndex", "CDShapeKey"};
 
 const CustomDataMask CD_MASK_BAREMESH =
-       CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE;
+       CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE | CD_MASK_MLOOP | CD_MASK_MPOLY;
 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_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS;
+       CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS |
+       CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MPOLY | CD_MASK_MLOOP |
+       CD_MASK_MTEXPOLY | CD_MASK_NORMAL | CD_MASK_MDISPS;
 const CustomDataMask CD_MASK_EDITMESH =
-       CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
-       CD_MASK_MCOL|CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS;
+       CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MLOOPUV |
+       CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_SHAPE_KEYINDEX |
+       CD_MASK_MCOL|CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR |
+       CD_MASK_MDISPS | CD_MASK_SHAPEKEY;
 const CustomDataMask CD_MASK_DERIVEDMESH =
        CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
        CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_PROP_FLT | CD_MASK_PROP_INT |
-       CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_TANGENT | CD_MASK_WEIGHT_MCOL;
-const CustomDataMask CD_MASK_BMESH = 
-       CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR;
+       CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_WEIGHT_MLOOPCOL |
+       CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_TANGENT | 
+       CD_MASK_WEIGHT_MCOL | CD_MASK_NORMAL;
+const CustomDataMask CD_MASK_BMESH = CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY |
+       CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | 
+       CD_MASK_PROP_STR | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_MDISPS;
 const CustomDataMask CD_MASK_FACECORNERS =
        CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV |
        CD_MASK_MLOOPCOL;
 
-
 static const LayerTypeInfo *layerType_getInfo(int type)
 {
        if(type < 0 || type >= CD_NUMTYPES) return NULL;
@@ -846,13 +1024,29 @@ static void customData_update_offsets(CustomData *data);
 static CustomDataLayer *customData_add_layer__internal(CustomData *data,
        int type, int alloctype, void *layerdata, int totelem, const char *name);
 
+void customData_update_typemap(CustomData *data)
+{
+       int i, lasttype = -1;
+
+       for (i=0; i<CD_NUMTYPES; i++) {
+               data->typemap[i] = -1;
+       }
+
+       for (i=0; i<data->totlayer; i++) {
+               if (data->layers[i].type != lasttype) {
+                       data->typemap[data->layers[i].type] = i;
+               }
+               lasttype = data->layers[i].type;
+       }
+}
+
 void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
                       CustomDataMask mask, int alloctype, int totelem)
 {
        const LayerTypeInfo *typeInfo;
        CustomDataLayer *layer, *newlayer;
        int i, type, number = 0, lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0;
-
+       
        for(i = 0; i < source->totlayer; ++i) {
                layer = &source->layers[i];
                typeInfo = layerType_getInfo(layer->type);
@@ -872,7 +1066,7 @@ void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
 
                if(layer->flag & CD_FLAG_NOCOPY) continue;
                else if(!((int)mask & (int)(1 << (int)type))) continue;
-               else if(number < CustomData_number_of_layers(dest, type)) continue;
+               else if(number+1 < CustomData_number_of_layers(dest, type)) continue;
 
                if((alloctype == CD_ASSIGN) && (layer->flag & CD_FLAG_NOFREE))
                        newlayer = customData_add_layer__internal(dest, type, CD_REFERENCE,
@@ -888,6 +1082,8 @@ void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
                        newlayer->active_mask = lastmask;
                }
        }
+
+       customData_update_typemap(dest);
 }
 
 void CustomData_copy(const struct CustomData *source, struct CustomData *dest,
@@ -962,6 +1158,17 @@ int CustomData_get_layer_index(const CustomData *data, int type)
        return -1;
 }
 
+int CustomData_get_layer_index_n(const struct CustomData *data, int type, int n)
+{
+       int i; 
+
+       for(i=0; i < data->totlayer; ++i)
+               if(data->layers[i].type == type)
+                       return i + n;
+
+       return -1;      
+}
+
 int CustomData_get_named_layer_index(const CustomData *data, int type, char *name)
 {
        int i;
@@ -975,11 +1182,12 @@ int CustomData_get_named_layer_index(const CustomData *data, int type, char *nam
 
 int CustomData_get_active_layer_index(const CustomData *data, int type)
 {
-       int i;
+       if (!data->totlayer)
+               return -1;
 
-       for(i=0; i < data->totlayer; ++i)
-               if(data->layers[i].type == type)
-                       return i + data->layers[i].active;
+       if (data->typemap[type] != -1) {
+               return data->typemap[type] + data->layers[data->typemap[type]].active;
+       }
 
        return -1;
 }
@@ -1241,6 +1449,7 @@ void *CustomData_add_layer(CustomData *data, int type, int alloctype,
        
        layer = customData_add_layer__internal(data, type, alloctype, layerdata,
                                               totelem, typeInfo->defaultname);
+       customData_update_typemap(data);
 
        if(layer)
                return layer->data;
@@ -1256,6 +1465,7 @@ void *CustomData_add_layer_named(CustomData *data, int type, int alloctype,
        
        layer = customData_add_layer__internal(data, type, alloctype, layerdata,
                                               totelem, name);
+       customData_update_typemap(data);
 
        if(layer)
                return layer->data;
@@ -1294,6 +1504,7 @@ int CustomData_free_layer(CustomData *data, int type, int totelem, int index)
                customData_resize(data, -CUSTOMDATA_GROW);
 
        customData_update_offsets(data);
+       customData_update_typemap(data);
 
        return 1;
 }
@@ -1403,6 +1614,16 @@ void CustomData_set_only_copy(const struct CustomData *data,
                        data->layers[i].flag |= CD_FLAG_NOCOPY;
 }
 
+void CustomData_copy_elements(int type, void *source, void *dest, int count)
+{
+       const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+       if (typeInfo->copy)
+               typeInfo->copy(source, dest, count);
+       else
+               memcpy(dest, source, typeInfo->size*count);
+}
+
 void CustomData_copy_data(const CustomData *source, CustomData *dest,
                           int source_index, int dest_index, int count)
 {
@@ -1562,6 +1783,19 @@ void *CustomData_get(const CustomData *data, int index, int type)
        return (char *)data->layers[layer_index].data + offset;
 }
 
+void *CustomData_get_n(const CustomData *data, int type, int index, int n)
+{
+       int layer_index;
+       int offset;
+
+       /* get the layer index of the first layer of type */
+       layer_index = data->typemap[type];
+       if(layer_index < 0) return NULL;
+       
+       offset = layerType_getInfo(type)->size * index;
+       return (char *)data->layers[layer_index+n].data + offset;
+}
+
 void *CustomData_get_layer(const CustomData *data, int type)
 {
        /* get the layer index of the active layer of type */
@@ -1896,17 +2130,18 @@ void CustomData_from_em_block(const CustomData *source, CustomData *dest,
 
 /*Bmesh functions*/
 /*needed to convert to/from different face reps*/
-void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata)
+void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata,
+                            int totloop, int totpoly)
 {
        int i;
        for(i=0; i < fdata->totlayer; i++){
                if(fdata->layers[i].type == CD_MTFACE){
-                       CustomData_add_layer(pdata, CD_MTEXPOLY, CD_CALLOC, &(fdata->layers[i].name), 0);
-                       CustomData_add_layer(ldata, CD_MLOOPUV, CD_CALLOC, &(fdata->layers[i].name), 0);
+                       CustomData_add_layer(pdata, CD_MTEXPOLY, CD_CALLOC, &(fdata->layers[i].name), totpoly);
+                       CustomData_add_layer(ldata, CD_MLOOPUV, CD_CALLOC, &(fdata->layers[i].name), totloop);
                }
                else if(fdata->layers[i].type == CD_MCOL)
-                       CustomData_add_layer(ldata, CD_MLOOPCOL, CD_CALLOC, &(fdata->layers[i].name), 0);
-       }               
+                       CustomData_add_layer(ldata, CD_MLOOPCOL, CD_CALLOC, &(fdata->layers[i].name), totloop);
+       }
 }
 void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata, int total){
        int i;
@@ -1917,12 +2152,62 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData
        for(i=0; i < ldata->totlayer; i++){
                if(ldata->layers[i].type == CD_MLOOPCOL)
                        CustomData_add_layer(fdata, CD_MCOL, CD_CALLOC, &(ldata->layers[i].name), total);
+               if (ldata->layers[i].type == CD_WEIGHT_MLOOPCOL)
+                       CustomData_add_layer(fdata, CD_WEIGHT_MCOL, CD_CALLOC, &(ldata->layers[i].name), total);
        }
 }
 
 
 void CustomData_bmesh_init_pool(CustomData *data, int allocsize){
-       if(data->totlayer)data->pool = BLI_mempool_create(data->totsize, allocsize, allocsize, 0);
+       if(data->totlayer)data->pool = BLI_mempool_create(data->totsize, allocsize, allocsize, 1);
+}
+
+void CustomData_bmesh_merge(CustomData *source, CustomData *dest, 
+                            int mask, int alloctype, BMesh *bm, int type)
+{
+       BMHeader *h;
+       BMIter iter;
+       CustomData destold = *dest;
+       void *tmp;
+       int t;
+       
+       CustomData_merge(source, dest, mask, alloctype, 0);
+       CustomData_bmesh_init_pool(dest, 512);
+
+       switch (type) {
+               case BM_VERT:
+                       t = BM_VERTS_OF_MESH; break;
+               case BM_EDGE:
+                       t = BM_EDGES_OF_MESH; break;
+               case BM_LOOP:
+                       t = BM_LOOPS_OF_FACE; break;
+               case BM_FACE:
+                       t = BM_FACES_OF_MESH; break;
+       }
+
+       if (t != BM_LOOPS_OF_FACE) {
+               /*ensure all current elements follow new customdata layout*/
+               BM_ITER(h, &iter, bm, t, NULL) {
+                       CustomData_bmesh_copy_data(&destold, dest, h->data, &tmp);
+                       CustomData_bmesh_free_block(&destold, &h->data);
+                       h->data = tmp;
+               }
+       } else {
+               BMFace *f;
+               BMLoop *l;
+               BMIter liter;
+
+               /*ensure all current elements follow new customdata layout*/
+               BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+                       BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+                               CustomData_bmesh_copy_data(&destold, dest, l->head.data, &tmp);
+                               CustomData_bmesh_free_block(&destold, &l->head.data);
+                               l->head.data = tmp;
+                       }
+               }
+       }
+
+       if (destold.pool) BLI_mempool_destroy(destold.pool);
 }
 
 void CustomData_bmesh_free_block(CustomData *data, void **block)
@@ -2026,6 +2311,82 @@ void *CustomData_bmesh_get_n(const CustomData *data, void *block, int type, int
        return (char *)block + data->layers[layer_index+n].offset;
 }
 
+/*gets from the layer at physical index n, note: doesn't check type.*/
+void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n)
+{
+       if(n < 0 || n >= data->totlayer) return NULL;
+
+       return (char *)block + data->layers[n].offset;
+}
+
+int CustomData_layer_has_math(struct CustomData *data, int layern)
+{
+       const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layern].type);
+       
+       if (typeInfo->equal && typeInfo->add && typeInfo->multiply && 
+           typeInfo->initminmax && typeInfo->dominmax) return 1;
+       
+       return 0;
+}
+
+/*copies the "value" (e.g. mloopuv uv or mloopcol colors) from one block to
+  another, while not overwriting anything else (e.g. flags)*/
+void CustomData_data_copy_value(int type, void *source, void *dest)
+{
+       const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+       if(!dest) return;
+
+       if(typeInfo->copyvalue)
+               typeInfo->copyvalue(source, dest);
+       else
+               memcpy(dest, source, typeInfo->size);
+}
+
+int CustomData_data_equals(int type, void *data1, void *data2)
+{
+       const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+       if (typeInfo->equal)
+               return typeInfo->equal(data1, data2);
+       else return !memcmp(data1, data2, typeInfo->size);
+}
+
+void CustomData_data_initminmax(int type, void *min, void *max)
+{
+       const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+       if (typeInfo->initminmax)
+               typeInfo->initminmax(min, max);
+}
+
+
+void CustomData_data_dominmax(int type, void *data, void *min, void *max)
+{
+       const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+       if (typeInfo->dominmax)
+               typeInfo->dominmax(data, min, max);
+}
+
+
+void CustomData_data_multiply(int type, void *data, float fac)
+{
+       const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+       if (typeInfo->multiply)
+               typeInfo->multiply(data, fac);
+}
+
+
+void CustomData_data_add(int type, void *data1, void *data2)
+{
+       const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+       if (typeInfo->add)
+               typeInfo->add(data1, data2);
+}
+
 void CustomData_bmesh_set(const CustomData *data, void *block, int type, void *source)
 {
        void *dest = CustomData_bmesh_get(data, block, type);
@@ -2052,6 +2413,19 @@ void CustomData_bmesh_set_n(CustomData *data, void *block, int type, int n, void
                memcpy(dest, source, typeInfo->size);
 }
 
+void CustomData_bmesh_set_layer_n(CustomData *data, void *block, int n, void *source)
+{
+       void *dest = CustomData_bmesh_get_layer_n(data, block, n);
+       const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type);
+
+       if(!dest) return;
+
+       if(typeInfo->copy)
+               typeInfo->copy(source, dest, 1);
+       else
+               memcpy(dest, source, typeInfo->size);
+}
+
 void CustomData_bmesh_interp(CustomData *data, void **src_blocks, float *weights,
                           float *sub_weights, int count, void *dest_block)
 {