Merged 15170:15635 from trunk (no conflicts or even merges)
[blender.git] / source / blender / blenkernel / intern / customdata.c
index 77068d8ed6647fa729b96966c8edf51ce6ed05e1..501293ecd814970d8ddc9a4e2a64cd4edc08a439 100644 (file)
@@ -36,6 +36,7 @@
 
 #include "BLI_blenlib.h"
 #include "BLI_linklist.h"
+#include "BLI_mempool.h"
 
 #include "DNA_customdata_types.h"
 #include "DNA_listBase.h"
@@ -359,8 +360,80 @@ static void layerDefault_origspace_face(void *data, int count)
 }
 /* --------- */
 
+static void layerDefault_mloopcol(void *data, int count)
+{
+       static MLoopCol default_mloopcol = {255,255,255,255};
+       MLoopCol *mlcol = (MLoopCol*)data;
+       int i;
+       for(i = 0; i < count; i++)
+               mlcol[i] = default_mloopcol;
+
+}
+
+static void layerInterp_mloopcol(void **sources, float *weights,
+                               float *sub_weights, int count, void *dest)
+{
+       MLoopCol *mc = dest;
+       int i;
+       float *sub_weight;
+       struct {
+               float a;
+               float r;
+               float g;
+               float b;
+       } col;
+       col.a = col.r = col.g = col.b = 0;
 
+       sub_weight = sub_weights;
+       for(i = 0; i < count; ++i){
+               float weight = weights ? weights[i] : 1;
+               MLoopCol *src = sources[i];
+               if(sub_weights){
+                       col.a += src->a * (*sub_weight) * weight;
+                       col.r += src->r * (*sub_weight) * weight;
+                       col.g += src->g * (*sub_weight) * weight;
+                       col.b += src->b * (*sub_weight) * weight;
+                       sub_weight++;           
+               } else {
+                       col.a += src->a * weight;
+                       col.r += src->r * weight;
+                       col.g += src->g * weight;
+                       col.b += src->b * weight;
+               }
+       }
+       mc->a = (int)col.a;
+       mc->r = (int)col.r;
+       mc->g = (int)col.g;
+       mc->b = (int)col.b;
+}
+static void layerInterp_mloopuv(void **sources, float *weights,
+                               float *sub_weights, int count, void *dest)
+{
+       MLoopUV *mluv = dest;
+       int i;
+       float *sub_weight;
+       struct {
+               float u;
+               float v;
+       }uv;
+       uv.u = uv.v = 0.0;
 
+       sub_weight = sub_weights;
+       for(i = 0; i < count; ++i){
+               float weight = weights ? weights[i] : 1;
+               MLoopUV *src = sources[i];
+               if(sub_weights){
+                       uv.u += src->uv[0] * (*sub_weight) * weight;
+                       uv.v += src->uv[1] * (*sub_weight) * weight;
+                       sub_weight++;           
+               } else {
+                       uv.u += src->uv[0] * weight;
+                       uv.v += src->uv[1] * weight;
+               }
+       }
+       mluv->uv[0] = uv.u;
+       mluv->uv[1] = uv.v;
+}
 
 static void layerInterp_mcol(void **sources, float *weights,
                              float *sub_weights, int count, void *dest)
@@ -432,6 +505,8 @@ static void layerDefault_mcol(void *data, int count)
                mcol[i] = default_mcol;
 }
 
+
+
 const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
        {sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL},
        {sizeof(MSticky), "MSticky", 1, NULL, NULL, NULL, layerInterp_msticky, NULL,
@@ -454,13 +529,16 @@ const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
        {sizeof(MStringProperty), "MStringProperty",1,"String",NULL,NULL,NULL,NULL},
        {sizeof(OrigSpaceFace), "OrigSpaceFace", 1, "UVTex", layerCopy_origspace_face, NULL,
         layerInterp_origspace_face, layerSwap_origspace_face, layerDefault_origspace_face},
-       {sizeof(float)*3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL}
+       {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} 
 };
 
 const char *LAYERTYPENAMES[CD_NUMTYPES] = {
        "CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace", "CDMTFace",
        "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags","CDMFloatProperty",
-       "CDMIntProperty","CDMStringProperty", "CDOrigSpace", "CDOrco"};
+       "CDMIntProperty","CDMStringProperty", "CDOrigSpace", "CDOrco", "CDMTexPoly", "CDMLoopUV", "CDMloopCol"};
 
 const CustomDataMask CD_MASK_BAREMESH =
        CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE;
@@ -475,6 +553,12 @@ 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;
+const CustomDataMask CD_MASK_BMESH = 
+       CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR;
+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)
 {
@@ -1449,6 +1533,302 @@ 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)
+{
+       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);
+               }
+               else if(fdata->layers[i].type == CD_MCOL)
+                       CustomData_add_layer(ldata, CD_MLOOPCOL, CD_CALLOC, &(fdata->layers[i].name), 0);
+       }               
+}
+void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata, int total){
+       int i;
+       for(i=0; i < pdata->totlayer; i++){
+               if(pdata->layers[i].type == CD_MTEXPOLY)
+                       CustomData_add_layer(fdata, CD_MTFACE, CD_CALLOC, &(pdata->layers[i].name), total);
+       }
+       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);
+       }
+}
+
+
+void CustomData_bmesh_init_pool(CustomData *data, int allocsize){
+       if(data->totlayer)data->pool = BLI_mempool_create(data->totsize, allocsize, allocsize);
+}
+
+void CustomData_bmesh_free_block(CustomData *data, void **block)
+{
+    const LayerTypeInfo *typeInfo;
+    int i;
+
+       if(!*block) return;
+    for(i = 0; i < data->totlayer; ++i) {
+        if(!(data->layers[i].flag & CD_FLAG_NOFREE)) {
+            typeInfo = layerType_getInfo(data->layers[i].type);
+
+            if(typeInfo->free) {
+                               int offset = data->layers[i].offset;
+                               typeInfo->free((char*)*block + offset, 1, typeInfo->size);
+                       }
+        }
+    }
+
+       BLI_mempool_free(data->pool, *block);
+       *block = NULL;
+}
+
+static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
+{
+
+       if (*block)
+               CustomData_bmesh_free_block(data, block);
+
+       if (data->totsize > 0)
+               *block = BLI_mempool_calloc(data->pool);
+       else
+               *block = NULL;
+}
+
+void CustomData_bmesh_copy_data(const CustomData *source, CustomData *dest,
+                            void *src_block, void **dest_block)
+{
+       const LayerTypeInfo *typeInfo;
+       int dest_i, src_i;
+
+       if (!*dest_block)
+               CustomData_bmesh_alloc_block(dest, dest_block);
+       
+       /* copies a layer at a time */
+       dest_i = 0;
+       for(src_i = 0; src_i < source->totlayer; ++src_i) {
+
+               /* find the first dest layer with type >= the source type
+                * (this should work because layers are ordered by type)
+                */
+               while(dest_i < dest->totlayer
+                     && dest->layers[dest_i].type < source->layers[src_i].type)
+                       ++dest_i;
+
+               /* if there are no more dest layers, we're done */
+               if(dest_i >= dest->totlayer) return;
+
+               /* if we found a matching layer, copy the data */
+               if(dest->layers[dest_i].type == source->layers[src_i].type &&
+                       strcmp(dest->layers[dest_i].name, source->layers[src_i].name) == 0) {
+                       char *src_data = (char*)src_block + source->layers[src_i].offset;
+                       char *dest_data = (char*)*dest_block + dest->layers[dest_i].offset;
+
+                       typeInfo = layerType_getInfo(source->layers[src_i].type);
+
+                       if(typeInfo->copy)
+                               typeInfo->copy(src_data, dest_data, 1);
+                       else
+                               memcpy(dest_data, src_data, typeInfo->size);
+
+                       /* if there are multiple source & dest layers of the same type,
+                        * we don't want to copy all source layers to the same dest, so
+                        * increment dest_i
+                        */
+                       ++dest_i;
+               }
+       }
+}
+
+/*Bmesh Custom Data Functions. Should replace editmesh ones with these as well, due to more effecient memory alloc*/
+void *CustomData_bmesh_get(const CustomData *data, void *block, int type)
+{
+       int layer_index;
+       
+       /* get the layer index of the first layer of type */
+       layer_index = CustomData_get_active_layer_index(data, type);
+       if(layer_index < 0) return NULL;
+
+       return (char *)block + data->layers[layer_index].offset;
+}
+
+void *CustomData_bmesh_get_n(const CustomData *data, void *block, int type, int n)
+{
+       int layer_index;
+       
+       /* get the layer index of the first layer of type */
+       layer_index = CustomData_get_layer_index(data, type);
+       if(layer_index < 0) return NULL;
+
+       return (char *)block + data->layers[layer_index+n].offset;
+}
+
+void CustomData_bmesh_set(const CustomData *data, void *block, int type, void *source)
+{
+       void *dest = CustomData_bmesh_get(data, block, type);
+       const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+       if(!dest) return;
+
+       if(typeInfo->copy)
+               typeInfo->copy(source, dest, 1);
+       else
+               memcpy(dest, source, typeInfo->size);
+}
+
+void CustomData_bmesh_set_n(CustomData *data, void *block, int type, int n, void *source)
+{
+       void *dest = CustomData_bmesh_get_n(data, block, type, n);
+       const LayerTypeInfo *typeInfo = layerType_getInfo(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)
+{
+       int i, j;
+       void *source_buf[SOURCE_BUF_SIZE];
+       void **sources = source_buf;
+
+       /* slow fallback in case we're interpolating a ridiculous number of
+        * elements
+        */
+       if(count > SOURCE_BUF_SIZE)
+               sources = MEM_callocN(sizeof(*sources) * count,
+                                     "CustomData_interp sources");
+
+       /* interpolates a layer at a time */
+       for(i = 0; i < data->totlayer; ++i) {
+               CustomDataLayer *layer = &data->layers[i];
+               const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
+               if(typeInfo->interp) {
+                       for(j = 0; j < count; ++j)
+                               sources[j] = (char *)src_blocks[j] + layer->offset;
+
+                       typeInfo->interp(sources, weights, sub_weights, count,
+                                         (char *)dest_block + layer->offset);
+               }
+       }
+
+       if(count > SOURCE_BUF_SIZE) MEM_freeN(sources);
+}
+
+void CustomData_bmesh_set_default(CustomData *data, void **block)
+{
+       const LayerTypeInfo *typeInfo;
+       int i;
+
+       if (!*block)
+               CustomData_bmesh_alloc_block(data, block);
+
+       for(i = 0; i < data->totlayer; ++i) {
+               int offset = data->layers[i].offset;
+
+               typeInfo = layerType_getInfo(data->layers[i].type);
+
+               if(typeInfo->set_default)
+                       typeInfo->set_default((char*)*block + offset, 1);
+       }
+}
+
+void CustomData_to_bmesh_block(const CustomData *source, CustomData *dest,
+                            int src_index, void **dest_block)
+{
+       const LayerTypeInfo *typeInfo;
+       int dest_i, src_i, src_offset;
+
+       if (!*dest_block)
+               CustomData_bmesh_alloc_block(dest, dest_block);
+       
+       /* copies a layer at a time */
+       dest_i = 0;
+       for(src_i = 0; src_i < source->totlayer; ++src_i) {
+
+               /* find the first dest layer with type >= the source type
+                * (this should work because layers are ordered by type)
+                */
+               while(dest_i < dest->totlayer
+                     && dest->layers[dest_i].type < source->layers[src_i].type)
+                       ++dest_i;
+
+               /* if there are no more dest layers, we're done */
+               if(dest_i >= dest->totlayer) return;
+
+               /* if we found a matching layer, copy the data */
+               if(dest->layers[dest_i].type == source->layers[src_i].type) {
+                       int offset = dest->layers[dest_i].offset;
+                       char *src_data = source->layers[src_i].data;
+                       char *dest_data = (char*)*dest_block + offset;
+
+                       typeInfo = layerType_getInfo(dest->layers[dest_i].type);
+                       src_offset = src_index * typeInfo->size;
+
+                       if(typeInfo->copy)
+                               typeInfo->copy(src_data + src_offset, dest_data, 1);
+                       else
+                               memcpy(dest_data, src_data + src_offset, typeInfo->size);
+
+                       /* if there are multiple source & dest layers of the same type,
+                        * we don't want to copy all source layers to the same dest, so
+                        * increment dest_i
+                        */
+                       ++dest_i;
+               }
+       }
+}
+
+void CustomData_from_bmesh_block(const CustomData *source, CustomData *dest,
+                              void *src_block, int dest_index)
+{
+       const LayerTypeInfo *typeInfo;
+       int dest_i, src_i, dest_offset;
+
+       /* copies a layer at a time */
+       dest_i = 0;
+       for(src_i = 0; src_i < source->totlayer; ++src_i) {
+
+               /* find the first dest layer with type >= the source type
+                * (this should work because layers are ordered by type)
+                */
+               while(dest_i < dest->totlayer
+                     && dest->layers[dest_i].type < source->layers[src_i].type)
+                       ++dest_i;
+
+               /* if there are no more dest layers, we're done */
+               if(dest_i >= dest->totlayer) return;
+
+               /* if we found a matching layer, copy the data */
+               if(dest->layers[dest_i].type == source->layers[src_i].type) {
+                       int offset = source->layers[src_i].offset;
+                       char *src_data = (char*)src_block + offset;
+                       char *dest_data = dest->layers[dest_i].data;
+
+                       typeInfo = layerType_getInfo(dest->layers[dest_i].type);
+                       dest_offset = dest_index * typeInfo->size;
+
+                       if(typeInfo->copy)
+                               typeInfo->copy(src_data, dest_data + dest_offset, 1);
+                       else
+                               memcpy(dest_data + dest_offset, src_data, typeInfo->size);
+
+                       /* if there are multiple source & dest layers of the same type,
+                        * we don't want to copy all source layers to the same dest, so
+                        * increment dest_i
+                        */
+                       ++dest_i;
+               }
+       }
+
+}
+
 void CustomData_file_write_info(int type, char **structname, int *structnum)
 {
        const LayerTypeInfo *typeInfo = layerType_getInfo(type);