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:
authorBastien Montagne <montagne29@wanadoo.fr>2015-01-09 21:11:40 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2015-01-09 21:32:44 +0300
commitee4453f08369d8cf910a88763bfb14392ea489cf (patch)
treee134c9f97feed70bcd0ccfea830cb497af8ac37d /source/blender/blenkernel/intern/customdata.c
parent67b1412bc956c857843db0551ce1ac426414f7c2 (diff)
Transfer Data: add main core code and operators.
This add code needed to map a CD data layout from source mesh towards destination one, and code needed to actually transfer data, using BKE's mesh remap generated data. This allows to transfer most CD layers (vgroups, vcols, uvs...) as well as fake, boolean ones (like smooth/sharp edges/faces, etc.). Some types are not yet transferable, mainly shape keys, this is known TODO. Data transfer can also use some advanced mixing in some cases (mostly, vgroups and vcols). Notes: * New transfer operators transfer data from active object towards selected ones. * Modifier will be committed separately. * Old weight transfer code (for vgroups) is kept for now, mostly because it is the only usable one in weightpaint mode (it transfers from selected object to active one, this is not sensible in Object mode, but needed in WeightPaint one). This will be addressed soon. Again, heavily reviewed and enhanced by Campbell, thanks!
Diffstat (limited to 'source/blender/blenkernel/intern/customdata.c')
-rw-r--r--source/blender/blenkernel/intern/customdata.c331
1 files changed, 317 insertions, 14 deletions
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 5e86ca596cf..856f893e876 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -48,6 +48,7 @@
#include "BLI_string.h"
#include "BLI_path_util.h"
#include "BLI_math.h"
+#include "BLI_math_color_blend.h"
#include "BLI_mempool.h"
#include "BLF_translation.h"
@@ -56,6 +57,8 @@
#include "BKE_customdata_file.h"
#include "BKE_global.h"
#include "BKE_main.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_remap.h"
#include "BKE_multires.h"
#include "bmesh.h"
@@ -92,7 +95,7 @@ typedef struct LayerTypeInfo {
* (deep copy if appropriate)
* if NULL, memcpy is used
*/
- void (*copy)(const void *source, void *dest, int count);
+ cd_copy copy;
/**
* a function to free any dynamically allocated components of this
@@ -117,8 +120,7 @@ typedef struct LayerTypeInfo {
* applying changes while reading from sources.
* See bug [#32395] - Campbell.
*/
- void (*interp)(void **sources, const float *weights, const float *sub_weights,
- int count, void *dest);
+ cd_interp interp;
/** a function to swap the data in corners of the element */
void (*swap)(void *data, const int *corner_indices);
@@ -134,7 +136,7 @@ typedef struct LayerTypeInfo {
void (*initminmax)(void *min, void *max);
void (*add)(void *data1, const void *data2);
void (*dominmax)(const void *data1, void *min, void *max);
- void (*copyvalue)(const void *source, void *dest);
+ void (*copyvalue)(const void *source, void *dest, const int mixmode, const float mixfactor);
/** a function to read data from a cdf file */
int (*read)(CDataFile *cdf, void *data, int count);
@@ -620,14 +622,53 @@ static void layerFree_grid_paint_mask(void *data, int count, int UNUSED(size))
}
/* --------- */
-static void layerCopyValue_mloopcol(const void *source, void *dest)
+static void layerCopyValue_mloopcol(const void *source, void *dest, const int mixmode, const float mixfactor)
{
const MLoopCol *m1 = source;
MLoopCol *m2 = dest;
-
- m2->r = m1->r;
- m2->g = m1->g;
- m2->b = m1->b;
+ unsigned char tmp_col[4];
+
+ if (ELEM(mixmode, CDT_MIX_NOMIX, CDT_MIX_REPLACE_ABOVE_THRESHOLD, CDT_MIX_REPLACE_BELOW_THRESHOLD)) {
+ /* Modes that do a full copy or nothing. */
+ if (ELEM(mixmode, CDT_MIX_REPLACE_ABOVE_THRESHOLD, CDT_MIX_REPLACE_BELOW_THRESHOLD)) {
+ /* TODO: Check for a real valid way to get 'factor' value of our dest color? */
+ const float f = ((float)m2->r + (float)m2->g + (float)m2->b) / 3.0f;
+ if (mixmode == CDT_MIX_REPLACE_ABOVE_THRESHOLD && f < mixfactor) {
+ return; /* Do Nothing! */
+ }
+ else if (mixmode == CDT_MIX_REPLACE_BELOW_THRESHOLD && f > mixfactor) {
+ return; /* Do Nothing! */
+ }
+ }
+ m2->r = m1->r;
+ m2->g = m1->g;
+ m2->b = m1->b;
+ }
+ else { /* Modes that support 'real' mix factor. */
+ unsigned char src[4] = {m1->r, m1->g, m1->b, m1->a};
+ unsigned char dst[4] = {m2->r, m2->g, m2->b, m2->a};
+
+ if (mixmode == CDT_MIX_MIX) {
+ blend_color_mix_byte(tmp_col, dst, src);
+ }
+ else if (mixmode == CDT_MIX_ADD) {
+ blend_color_add_byte(tmp_col, dst, src);
+ }
+ else if (mixmode == CDT_MIX_SUB) {
+ blend_color_sub_byte(tmp_col, dst, src);
+ }
+ else if (mixmode == CDT_MIX_MUL) {
+ blend_color_mul_byte(tmp_col, dst, src);
+ }
+ else {
+ memcpy(tmp_col, src, sizeof(tmp_col));
+ }
+ blend_color_interpolate_byte(dst, dst, tmp_col, mixfactor);
+
+ m2->r = (char)dst[0];
+ m2->g = (char)dst[1];
+ m2->b = (char)dst[2];
+ }
m2->a = m1->a;
}
@@ -758,12 +799,19 @@ static int layerMaxNum_mloopcol(void)
return MAX_MCOL;
}
-static void layerCopyValue_mloopuv(const void *source, void *dest)
+static void layerCopyValue_mloopuv(const void *source, void *dest, const int mixmode, const float mixfactor)
{
const MLoopUV *luv1 = source;
MLoopUV *luv2 = dest;
- copy_v2_v2(luv2->uv, luv1->uv);
+ /* We only support a limited subset of advanced mixing here - namely the mixfactor interpolation. */
+
+ if (mixmode == CDT_MIX_NOMIX) {
+ copy_v2_v2(luv2->uv, luv1->uv);
+ }
+ else {
+ interp_v2_v2v2(luv2->uv, luv2->uv, luv1->uv, mixfactor);
+ }
}
static bool layerEqual_mloopuv(const void *data1, const void *data2)
@@ -833,7 +881,8 @@ static void layerInterp_mloopuv(void **sources, const float *weights,
}
/* origspace is almost exact copy of mloopuv's, keep in sync */
-static void layerCopyValue_mloop_origspace(const void *source, void *dest)
+static void layerCopyValue_mloop_origspace(const void *source, void *dest,
+ const int UNUSED(mixmode), const float UNUSED(mixfactor))
{
const OrigSpaceLoop *luv1 = source;
OrigSpaceLoop *luv2 = dest;
@@ -2261,7 +2310,7 @@ int CustomData_get_n_offset(const CustomData *data, int type, int n)
bool CustomData_set_layer_name(const CustomData *data, int type, int n, const char *name)
{
/* get the layer index of the first layer of type */
- int layer_index = CustomData_get_layer_index_n(data, type, n);
+ const int layer_index = CustomData_get_layer_index_n(data, type, n);
if ((layer_index == -1) || !name)
return false;
@@ -2271,6 +2320,13 @@ bool CustomData_set_layer_name(const CustomData *data, int type, int n, const ch
return true;
}
+const char *CustomData_get_layer_name(const CustomData *data, int type, int n)
+{
+ const int layer_index = CustomData_get_layer_index_n(data, type, n);
+
+ return (layer_index == -1) ? NULL : data->layers[layer_index].name;
+}
+
void *CustomData_set_layer(const CustomData *data, int type, void *ptr)
{
/* get the layer index of the first layer of type */
@@ -2764,11 +2820,28 @@ void CustomData_data_copy_value(int type, const void *source, void *dest)
if (!dest) return;
if (typeInfo->copyvalue)
- typeInfo->copyvalue(source, dest);
+ typeInfo->copyvalue(source, dest, CDT_MIX_NOMIX, 0.0f);
else
memcpy(dest, source, typeInfo->size);
}
+/* Mixes the "value" (e.g. mloopuv uv or mloopcol colors) from one block into
+ * another, while not overwriting anything else (e.g. flags)*/
+void CustomData_data_mix_value(int type, const void *source, void *dest, const int mixmode, const float mixfactor)
+{
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+ if (!dest) return;
+
+ if (typeInfo->copyvalue) {
+ typeInfo->copyvalue(source, dest, mixmode, mixfactor);
+ }
+ else {
+ /* Mere copy if no advanced interpolation is supported. */
+ memcpy(dest, source, typeInfo->size);
+ }
+}
+
bool CustomData_data_equals(int type, const void *data1, const void *data2)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
@@ -3464,3 +3537,233 @@ void CustomData_external_remove_object(CustomData *data, ID *id)
}
#endif
+/* ********** Mesh-to-mesh data transfer ********** */
+static void copy_bit_flag(void *dst, void *src, const size_t data_size, const uint64_t flag)
+{
+#define COPY_BIT_FLAG(_type, _dst, _src, _f) \
+{ \
+ const _type _val = *((_type *)(_src)) & ((_type)(_f)); \
+ *((_type *)(_dst)) &= ~((_type)(_f)); \
+ *((_type *)(_dst)) |= _val; \
+} (void) 0
+
+ switch (data_size) {
+ case 1:
+ COPY_BIT_FLAG(uint8_t, dst, src, flag);
+ break;
+ case 2:
+ COPY_BIT_FLAG(uint16_t, dst, src, flag);
+ break;
+ case 4:
+ COPY_BIT_FLAG(uint32_t, dst, src, flag);
+ break;
+ case 8:
+ COPY_BIT_FLAG(uint64_t, dst, src, flag);
+ break;
+ default:
+ //printf("ERROR %s: Unknown flags-container size (%zu)\n", __func__, datasize);
+ break;
+ }
+
+#undef COPY_BIT_FLAG
+}
+
+static bool check_bit_flag(void *data, const size_t data_size, const uint64_t flag)
+{
+ switch (data_size) {
+ case 1:
+ return ((*((uint8_t *)data) & ((uint8_t)flag)) != 0);
+ case 2:
+ return ((*((uint16_t *)data) & ((uint16_t)flag)) != 0);
+ case 4:
+ return ((*((uint32_t *)data) & ((uint32_t)flag)) != 0);
+ case 8:
+ return ((*((uint64_t *)data) & ((uint64_t)flag)) != 0);
+ default:
+ //printf("ERROR %s: Unknown flags-container size (%zu)\n", __func__, datasize);
+ return false;
+ }
+}
+
+static void customdata_data_transfer_interp_generic(
+ const CustomDataTransferLayerMap *laymap, void *data_dst, void **sources, const float *weights, const int count,
+ const float mix_factor)
+{
+ /* Fake interpolation, we actually copy highest weighted source to dest.
+ * Note we also handle bitflags here, in which case we rather choose to transfer value of elements totalizing
+ * more than 0.5 of weight. */
+
+ int best_src_idx = 0;
+
+ const int data_type = laymap->data_type;
+ const int mix_mode = laymap->mix_mode;
+
+ size_t data_size;
+ const uint64_t data_flag = laymap->data_flag;
+
+ cd_interp interp_cd = NULL;
+ cd_copy copy_cd = NULL;
+
+ void *tmp_dst;
+
+ if (!sources) {
+ /* Not supported here, abort. */
+ return;
+ }
+
+ if (data_type & CD_FAKE) {
+ data_size = laymap->data_size;
+ }
+ else {
+ const LayerTypeInfo *type_info = layerType_getInfo(data_type);
+
+ data_size = (size_t)type_info->size;
+ interp_cd = type_info->interp;
+ copy_cd = type_info->copy;
+ }
+
+ tmp_dst = MEM_mallocN(data_size, __func__);
+
+ if (count > 1 && !interp_cd) {
+ int i;
+
+ if (data_flag) {
+ /* Boolean case, we can 'interpolate' in two groups, and choose value from highest weighted group. */
+ float tot_weight_true = 0.0f;
+ int item_true_idx = -1, item_false_idx = -1;
+
+ for (i = 0; i < count; i++) {
+ if (check_bit_flag(sources[i], data_size, data_flag)) {
+ tot_weight_true += weights[i];
+ item_true_idx = i;
+ }
+ else {
+ item_false_idx = i;
+ }
+ }
+ best_src_idx = (tot_weight_true >= 0.5f) ? item_true_idx : item_false_idx;
+ }
+ else {
+ /* We just choose highest weighted source. */
+ float max_weight = 0.0f;
+
+ for (i = 0; i < count; i++) {
+ if (weights[i] > max_weight) {
+ max_weight = weights[i];
+ best_src_idx = i;
+ }
+ }
+ }
+ }
+
+ BLI_assert(best_src_idx >= 0);
+
+ if (interp_cd) {
+ interp_cd(sources, weights, NULL, count, (char *)tmp_dst);
+ }
+ else if (data_flag) {
+ copy_bit_flag(tmp_dst, sources[best_src_idx], data_size, data_flag);
+ }
+ /* No interpolation, just copy highest weight source element's data. */
+ else if (copy_cd) {
+ copy_cd((char *)sources[best_src_idx], (char *)tmp_dst, 1);
+ }
+ else {
+ memcpy(tmp_dst, sources[best_src_idx], data_size);
+ }
+
+ if (data_flag) {
+ /* Bool flags, only copy if dest data is set (resp. unset) - only 'advanced' modes we can support here! */
+ if (mix_factor >= 0.5f &&
+ ((mix_mode == CDT_MIX_TRANSFER) ||
+ (mix_mode == CDT_MIX_REPLACE_ABOVE_THRESHOLD && check_bit_flag(data_dst, data_size, data_flag)) ||
+ (mix_mode == CDT_MIX_REPLACE_BELOW_THRESHOLD && !check_bit_flag(data_dst, data_size, data_flag))))
+ {
+ copy_bit_flag(data_dst, tmp_dst, data_size, data_flag);
+ }
+ }
+ else if (!(data_type & CD_FAKE)) {
+ CustomData_data_mix_value(data_type, tmp_dst, data_dst, mix_mode, mix_factor);
+ }
+ /* Else we can do nothing by default, needs custom interp func!
+ * Note this is here only for sake of consistency, not expected to be used much actually? */
+ else {
+ if (mix_factor >= 0.5f) {
+ memcpy(data_dst, tmp_dst, data_size);
+ }
+ }
+
+ MEM_freeN(tmp_dst);
+}
+
+void CustomData_data_transfer(const MeshPairRemap *me_remap, const CustomDataTransferLayerMap *laymap)
+{
+ MeshPairRemapItem *mapit = me_remap->items;
+ const int totelem = me_remap->items_num;
+ int i;
+
+ const int data_type = laymap->data_type;
+ void *data_src = laymap->data_src;
+ void *data_dst = laymap->data_dst;
+
+ size_t data_step;
+ size_t data_size;
+ size_t data_offset;
+
+ cd_datatransfer_interp interp = NULL;
+
+ size_t tmp_buff_size = 32;
+ void **tmp_data_src = NULL;
+
+ /* Note: NULL data_src may happen and be valid (see vgroups...). */
+ if (!data_dst) {
+ return;
+ }
+
+ if (data_src) {
+ tmp_data_src = MEM_mallocN(sizeof(*tmp_data_src) * tmp_buff_size, __func__);
+ }
+
+ if (data_type & CD_FAKE) {
+ data_step = laymap->elem_size;
+ data_size = laymap->data_size;
+ data_offset = laymap->data_offset;
+ }
+ else {
+ const LayerTypeInfo *type_info = layerType_getInfo(data_type);
+
+ /* Note: we can use 'fake' CDLayers, like e.g. for crease, bweight, etc. :/ */
+ data_size = (size_t)type_info->size;
+ data_step = laymap->elem_size ? laymap->elem_size : data_size;
+ data_offset = laymap->data_offset;
+ }
+
+ interp = laymap->interp ? laymap->interp : customdata_data_transfer_interp_generic;
+
+ for (i = 0; i < totelem; i++, data_dst = (char *)data_dst + data_step, mapit++) {
+ const int sources_num = mapit->sources_num;
+ const float mix_factor = laymap->mix_weights ? laymap->mix_weights[i] : laymap->mix_factor;
+ int j;
+
+ if (!sources_num) {
+ /* No sources for this element, skip it. */
+ continue;
+ }
+
+ if (tmp_data_src) {
+ if (UNLIKELY(sources_num > tmp_buff_size)) {
+ tmp_buff_size = (size_t)sources_num;
+ tmp_data_src = MEM_reallocN(tmp_data_src, sizeof(*tmp_data_src) * tmp_buff_size);
+ }
+
+ for (j = 0; j < sources_num; j++) {
+ const size_t src_idx = (size_t)mapit->indices_src[j];
+ tmp_data_src[j] = (char *)data_src + data_step * src_idx + data_offset;
+ }
+ }
+
+ interp(laymap, (char *)data_dst + data_offset, tmp_data_src, mapit->weights_src, sources_num, mix_factor);
+ }
+
+ MEM_SAFE_FREE(tmp_data_src);
+}