diff options
author | Campbell Barton <ideasman42@gmail.com> | 2012-08-23 21:16:11 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2012-08-23 21:16:11 +0400 |
commit | f6a6fa419ea667b05180b2608db3edc15f171dd0 (patch) | |
tree | 4f7f9b6ec2cada94a27fe07fc26551a4f8e4272f /source/blender/blenkernel/intern/customdata.c | |
parent | 65dbeabdc6a89506df40222c52a1fc1db8c19e39 (diff) |
fix [#32395] BMesh data interpolation feedback loop
Diffstat (limited to 'source/blender/blenkernel/intern/customdata.c')
-rw-r--r-- | source/blender/blenkernel/intern/customdata.c | 51 |
1 files changed, 49 insertions, 2 deletions
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index d4e23c365e8..c55f1b551e2 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -1962,6 +1962,23 @@ void CustomData_free_elem(CustomData *data, int index, int count) #define SOURCE_BUF_SIZE 100 +/* This define makes it so when we are interpolating customdata, + * the source is checked if it matches the destination. + * + * There are 2 ways to get around this, + * - Each interp function could accumulate the final result in a local, stack variable, + * then apply the result at the end. + * + * - Or we can make a temp copy of the destinations custom data before applying it. + * This isn't so efficient but avoids having to consider feedback loop on each interp function. + * Since this is more of a corner case its also not worth worrying about speed too much. + * + * (opted for the second option for now), keeping as an ifdef since we may wan't to change how works. + * + * see bug [#32395] - Campbell. + */ +#define USE_INTERP_OVERLAP_FIX + void CustomData_interp(const CustomData *source, CustomData *dest, int *src_indices, float *weights, float *sub_weights, int count, int dest_index) @@ -1999,8 +2016,12 @@ void CustomData_interp(const CustomData *source, CustomData *dest, if (dest->layers[dest_i].type == source->layers[src_i].type) { void *src_data = source->layers[src_i].data; - for (j = 0; j < count; ++j) + for (j = 0; j < count; ++j) { + /* if this happens we need to do a temp copy, see: USE_INTERP_OVERLAP_FIX */ + BLI_assert(dest_index != src_indices[j]); + sources[j] = (char *)src_data + typeInfo->size * src_indices[j]; + } dest_offset = dest_index * typeInfo->size; @@ -2578,6 +2599,11 @@ void CustomData_bmesh_interp(CustomData *data, void **src_blocks, float *weights void *source_buf[SOURCE_BUF_SIZE]; void **sources = source_buf; +#ifdef USE_INTERP_OVERLAP_FIX + /* incase there is overlap with the source */ + void *dest_block_copy = NULL; +#endif + /* slow fallback in case we're interpolating a ridiculous number of * elements */ @@ -2590,14 +2616,35 @@ void CustomData_bmesh_interp(CustomData *data, void **src_blocks, float *weights CustomDataLayer *layer = &data->layers[i]; const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if (typeInfo->interp) { - for (j = 0; j < count; ++j) + for (j = 0; j < count; ++j) { +#ifdef USE_INTERP_OVERLAP_FIX + void *src_block; + if (UNLIKELY(src_blocks[j] == dest_block)) { + if (dest_block_copy == NULL) { + CustomData_bmesh_copy_data(data, data, dest_block, &dest_block_copy); + } + src_block = dest_block_copy; + } + else { + src_block = src_blocks[j]; + } + sources[j] = (char *)src_block + layer->offset; +#else sources[j] = (char *)src_blocks[j] + layer->offset; +#endif + } typeInfo->interp(sources, weights, sub_weights, count, (char *)dest_block + layer->offset); } } +#ifdef USE_INTERP_OVERLAP_FIX + if (dest_block_copy) { + CustomData_bmesh_free_block(data, &dest_block_copy); + } +#endif + if (count > SOURCE_BUF_SIZE) MEM_freeN(sources); } |