static int datalayout_transfer_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Object *ob_act = ED_object_active_context(C); DataTransferModifierData *dtmd; dtmd = (DataTransferModifierData *)edit_modifier_property_get(op, ob_act, eModifierType_DataTransfer); /* If we have a modifier, we transfer data layout from this modifier's source object to active one. * Else, we transfer data layout from active object to all selected ones. */ if (dtmd) { Object *ob_src = dtmd->ob_source; Object *ob_dst = ob_act; const bool use_delete = false; /* Never when used from modifier, for now. */ if (!ob_src) { return OPERATOR_CANCELLED; } BKE_object_data_transfer_layout(scene, ob_src, ob_dst, dtmd->data_types, use_delete, dtmd->layers_select_src, dtmd->layers_select_dst); DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); } else { Object *ob_src = ob_act; ListBase ctx_objects; CollectionPointerLink *ctx_ob_dst; const int data_type = RNA_enum_get(op->ptr, "data_type"); const bool use_delete = RNA_boolean_get(op->ptr, "use_delete"); const int layers_src = RNA_enum_get(op->ptr, "layers_select_src"); const int layers_dst = RNA_enum_get(op->ptr, "layers_select_dst"); int layers_select_src[DT_MULTILAYER_INDEX_MAX] = {0}; int layers_select_dst[DT_MULTILAYER_INDEX_MAX] = {0}; const int fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(data_type); if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) { layers_select_src[fromto_idx] = layers_src; layers_select_dst[fromto_idx] = layers_dst; } data_transfer_exec_preprocess_objects(C, op, ob_src, &ctx_objects, false); for (ctx_ob_dst = ctx_objects.first; ctx_ob_dst; ctx_ob_dst = ctx_ob_dst->next) { Object *ob_dst = ctx_ob_dst->ptr.data; if (data_transfer_exec_is_object_valid(op, ob_src, ob_dst, false)) { BKE_object_data_transfer_layout(scene, ob_src, ob_dst, data_type, use_delete, layers_select_src, layers_select_dst); } DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); } BLI_freelistN(&ctx_objects); } WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); return OPERATOR_FINISHED; }
/** * Transfer data *layout* of selected types from source to destination object. * By default, it only creates new data layers if needed on \a ob_dst. * If \a use_delete is true, it will also delete data layers on \a ob_dst that do not match those from \a ob_src, * to get (as much as possible) exact copy of source data layout. */ void BKE_object_data_transfer_layout( Scene *scene, Object *ob_src, Object *ob_dst, const int data_types, const bool use_delete, const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX]) { DerivedMesh *dm_src; Mesh *me_dst; int i; const bool use_create = true; /* We always create needed layers here. */ CustomDataMask dm_src_mask = CD_MASK_BAREMESH; BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH)); me_dst = ob_dst->data; /* Get source DM.*/ dm_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types); dm_src = mesh_get_derived_final(scene, ob_src, dm_src_mask); if (!dm_src) { return; } /* Check all possible data types. */ for (i = 0; i < DT_TYPE_MAX; i++) { const int dtdata_type = 1 << i; int cddata_type; int fromlayers, tolayers, fromto_idx; if (!(data_types & dtdata_type)) { continue; } cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type); fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(dtdata_type); if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) { fromlayers = fromlayers_select[fromto_idx]; tolayers = tolayers_select[fromto_idx]; } else { fromlayers = tolayers = 0; } if (DT_DATATYPE_IS_VERT(dtdata_type)) { const int num_elem_dst = me_dst->totvert; data_transfer_layersmapping_generate( NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_VERT, cddata_type, 0, 0.0f, NULL, num_elem_dst, use_create, use_delete, fromlayers, tolayers); } if (DT_DATATYPE_IS_EDGE(dtdata_type)) { const int num_elem_dst = me_dst->totedge; data_transfer_layersmapping_generate( NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_EDGE, cddata_type, 0, 0.0f, NULL, num_elem_dst, use_create, use_delete, fromlayers, tolayers); } if (DT_DATATYPE_IS_LOOP(dtdata_type)) { const int num_elem_dst = me_dst->totloop; data_transfer_layersmapping_generate( NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_LOOP, cddata_type, 0, 0.0f, NULL, num_elem_dst, use_create, use_delete, fromlayers, tolayers); } if (DT_DATATYPE_IS_POLY(dtdata_type)) { const int num_elem_dst = me_dst->totpoly; data_transfer_layersmapping_generate( NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_POLY, cddata_type, 0, 0.0f, NULL, num_elem_dst, use_create, use_delete, fromlayers, tolayers); } } }
static int data_transfer_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Object *ob_src = ED_object_active_context(C); ListBase ctx_objects; CollectionPointerLink *ctx_ob_dst; bool changed = false; const bool is_frozen = RNA_boolean_get(op->ptr, "use_freeze"); const bool reverse_transfer = RNA_boolean_get(op->ptr, "use_reverse_transfer"); const int data_type = RNA_enum_get(op->ptr, "data_type"); const bool use_create = RNA_boolean_get(op->ptr, "use_create"); const int map_vert_mode = RNA_enum_get(op->ptr, "vert_mapping"); const int map_edge_mode = RNA_enum_get(op->ptr, "edge_mapping"); const int map_loop_mode = RNA_enum_get(op->ptr, "loop_mapping"); const int map_poly_mode = RNA_enum_get(op->ptr, "poly_mapping"); const bool use_auto_transform = RNA_boolean_get(op->ptr, "use_auto_transform"); const bool use_object_transform = RNA_boolean_get(op->ptr, "use_object_transform"); const bool use_max_distance = RNA_boolean_get(op->ptr, "use_max_distance"); const float max_distance = use_max_distance ? RNA_float_get(op->ptr, "max_distance") : FLT_MAX; const float ray_radius = RNA_float_get(op->ptr, "ray_radius"); const float islands_precision = RNA_float_get(op->ptr, "islands_precision"); const int layers_src = RNA_enum_get(op->ptr, "layers_select_src"); const int layers_dst = RNA_enum_get(op->ptr, "layers_select_dst"); int layers_select_src[DT_MULTILAYER_INDEX_MAX] = {0}; int layers_select_dst[DT_MULTILAYER_INDEX_MAX] = {0}; const int fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(data_type); const int mix_mode = RNA_enum_get(op->ptr, "mix_mode"); const float mix_factor = RNA_float_get(op->ptr, "mix_factor"); SpaceTransform space_transform_data; SpaceTransform *space_transform = (use_object_transform && !use_auto_transform) ? &space_transform_data : NULL; if (is_frozen) { BKE_report(op->reports, RPT_INFO, "Operator is frozen, changes to its settings won't take effect until you unfreeze it"); return OPERATOR_FINISHED; } if (reverse_transfer && ((ID *)(ob_src->data))->lib) { /* Do not transfer to linked data, not supported. */ return OPERATOR_CANCELLED; } if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) { layers_select_src[fromto_idx] = layers_src; layers_select_dst[fromto_idx] = layers_dst; } data_transfer_exec_preprocess_objects(C, op, ob_src, &ctx_objects, reverse_transfer); for (ctx_ob_dst = ctx_objects.first; ctx_ob_dst; ctx_ob_dst = ctx_ob_dst->next) { Object *ob_dst = ctx_ob_dst->ptr.data; if (reverse_transfer) { SWAP(Object *, ob_src, ob_dst); } if (data_transfer_exec_is_object_valid(op, ob_src, ob_dst, reverse_transfer)) { if (space_transform) { BLI_SPACE_TRANSFORM_SETUP(space_transform, ob_dst, ob_src); } if (BKE_object_data_transfer_mesh( scene, ob_src, ob_dst, data_type, use_create, map_vert_mode, map_edge_mode, map_loop_mode, map_poly_mode, space_transform, use_auto_transform, max_distance, ray_radius, islands_precision, layers_select_src, layers_select_dst, mix_mode, mix_factor, NULL, false, op->reports)) { changed = true; } } DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); if (reverse_transfer) { SWAP(Object *, ob_src, ob_dst); } } BLI_freelistN(&ctx_objects); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); #if 0 /* TODO */ /* Note: issue with that is that if canceled, operator cannot be redone... Nasty in our case. */ return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED; #else (void)changed; return OPERATOR_FINISHED; #endif }
bool BKE_object_data_transfer_dm( Scene *scene, Object *ob_src, Object *ob_dst, DerivedMesh *dm_dst, const int data_types, bool use_create, const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode, SpaceTransform *space_transform, const float max_distance, const float ray_radius, const float islands_handling_precision, const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX], const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup, ReportList *reports) { #define VDATA 0 #define EDATA 1 #define LDATA 2 #define PDATA 3 #define DATAMAX 4 DerivedMesh *dm_src; Mesh *me_dst, *me_src; bool dirty_nors_dst = true; /* Assumed always true if not using a dm as destination. */ int i; MDeformVert *mdef = NULL; int vg_idx = -1; float *weights[DATAMAX] = {NULL}; MeshPairRemap geom_map[DATAMAX] = {{0}}; bool geom_map_init[DATAMAX] = {0}; ListBase lay_map = {NULL}; bool changed = false; const bool use_delete = false; /* We never delete data layers from destination here. */ CustomDataMask dm_src_mask = CD_MASK_BAREMESH; BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH)); me_dst = ob_dst->data; me_src = ob_src->data; if (dm_dst) { dirty_nors_dst = (dm_dst->dirty & DM_DIRTY_NORMALS) != 0; use_create = false; /* Never create needed custom layers on DM (modifier case). */ } if (vgroup_name) { if (dm_dst) { mdef = dm_dst->getVertDataArray(dm_dst, CD_MDEFORMVERT); } else { mdef = CustomData_get_layer(&me_dst->vdata, CD_MDEFORMVERT); } if (mdef) { vg_idx = defgroup_name_index(ob_dst, vgroup_name); } } /* Get source DM.*/ dm_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types); /* XXX Hack! In case this is being evaluated from dm stack, we cannot compute final dm, * can lead to infinite recursion in case of dependency cycles of DataTransfer modifiers... * Issue is, this means we cannot be sure to have requested cd layers in source. */ dm_src = dm_dst ? ob_src->derivedFinal : mesh_get_derived_final(scene, ob_src, dm_src_mask); if (!dm_src) { return changed; } /* Check all possible data types. * Note item mappings and dest mix weights are cached. */ for (i = 0; i < DT_TYPE_MAX; i++) { const int dtdata_type = 1 << i; int cddata_type; int fromlayers, tolayers, fromto_idx; if (!(data_types & dtdata_type)) { continue; } data_transfer_dtdata_type_preprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst, dtdata_type, dirty_nors_dst, (me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh); cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type); fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(dtdata_type); if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) { fromlayers = fromlayers_select[fromto_idx]; tolayers = tolayers_select[fromto_idx]; } else { fromlayers = tolayers = 0; } if (DT_DATATYPE_IS_VERT(dtdata_type)) { MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; if (!geom_map_init[VDATA]) { const int num_verts_src = dm_src->getNumVerts(dm_src); if ((map_vert_mode == MREMAP_MODE_TOPOLOGY) && (num_verts_dst != num_verts_src)) { BKE_report(reports, RPT_ERROR, "Source and destination meshes do not have the same amount of vertices, " "'Topology' mapping cannot be used in this case"); return changed; } if (ELEM(0, num_verts_dst, num_verts_src)) { BKE_report(reports, RPT_ERROR, "Source or destination meshes do not have any vertices, cannot transfer vertex data"); return changed; } BKE_mesh_remap_calc_verts_from_dm( map_vert_mode, space_transform, max_distance, ray_radius, verts_dst, num_verts_dst, dirty_nors_dst, dm_src, &geom_map[VDATA]); geom_map_init[VDATA] = true; } if (mdef && vg_idx != -1 && !weights[VDATA]) { weights[VDATA] = MEM_mallocN(sizeof(*(weights[VDATA])) * (size_t)num_verts_dst, __func__); BKE_defvert_extract_vgroup_to_vertweights(mdef, vg_idx, num_verts_dst, weights[VDATA], invert_vgroup); } if (data_transfer_layersmapping_generate( &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_VERT, cddata_type, mix_mode, mix_factor, weights[VDATA], num_verts_dst, use_create, use_delete, fromlayers, tolayers)) { CustomDataTransferLayerMap *lay_mapit; changed = (lay_map.first != NULL); for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) { CustomData_data_transfer(&geom_map[VDATA], lay_mapit); } BLI_freelistN(&lay_map); } } if (DT_DATATYPE_IS_EDGE(dtdata_type)) { MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge; const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge; if (!geom_map_init[EDATA]) { const int num_edges_src = dm_src->getNumEdges(dm_src); if ((map_edge_mode == MREMAP_MODE_TOPOLOGY) && (num_edges_dst != num_edges_src)) { BKE_report(reports, RPT_ERROR, "Source and destination meshes do not have the same amount of edges, " "'Topology' mapping cannot be used in this case"); return changed; } if (ELEM(0, num_edges_dst, num_edges_src)) { BKE_report(reports, RPT_ERROR, "Source or destination meshes do not have any edges, cannot transfer edge data"); return changed; } BKE_mesh_remap_calc_edges_from_dm( map_edge_mode, space_transform, max_distance, ray_radius, verts_dst, num_verts_dst, edges_dst, num_edges_dst, dirty_nors_dst, dm_src, &geom_map[EDATA]); geom_map_init[EDATA] = true; } if (mdef && vg_idx != -1 && !weights[EDATA]) { weights[EDATA] = MEM_mallocN(sizeof(*weights[EDATA]) * (size_t)num_edges_dst, __func__); BKE_defvert_extract_vgroup_to_edgeweights( mdef, vg_idx, num_verts_dst, edges_dst, num_edges_dst, weights[EDATA], invert_vgroup); } if (data_transfer_layersmapping_generate( &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_EDGE, cddata_type, mix_mode, mix_factor, weights[EDATA], num_edges_dst, use_create, use_delete, fromlayers, tolayers)) { CustomDataTransferLayerMap *lay_mapit; changed = (lay_map.first != NULL); for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) { CustomData_data_transfer(&geom_map[EDATA], lay_mapit); } BLI_freelistN(&lay_map); } } if (DT_DATATYPE_IS_LOOP(dtdata_type)) { MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge; const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge; MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly; const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly; MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop; const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop; CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata; CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata; MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type); if (!geom_map_init[LDATA]) { const int num_loops_src = dm_src->getNumLoops(dm_src); if ((map_loop_mode == MREMAP_MODE_TOPOLOGY) && (num_loops_dst != num_loops_src)) { BKE_report(reports, RPT_ERROR, "Source and destination meshes do not have the same amount of face corners, " "'Topology' mapping cannot be used in this case"); return changed; } if (ELEM(0, num_loops_dst, num_loops_src)) { BKE_report(reports, RPT_ERROR, "Source or destination meshes do not have any polygons, cannot transfer loop data"); return changed; } BKE_mesh_remap_calc_loops_from_dm( map_loop_mode, space_transform, max_distance, ray_radius, verts_dst, num_verts_dst, edges_dst, num_edges_dst, loops_dst, num_loops_dst, polys_dst, num_polys_dst, ldata_dst, pdata_dst, (me_dst->flag & ME_AUTOSMOOTH) != 0, me_dst->smoothresh, dirty_nors_dst, dm_src, (me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh, island_callback, islands_handling_precision, &geom_map[LDATA]); geom_map_init[LDATA] = true; } if (mdef && vg_idx != -1 && !weights[LDATA]) { weights[LDATA] = MEM_mallocN(sizeof(*weights[LDATA]) * (size_t)num_loops_dst, __func__); BKE_defvert_extract_vgroup_to_loopweights( mdef, vg_idx, num_verts_dst, loops_dst, num_loops_dst, weights[LDATA], invert_vgroup); } if (data_transfer_layersmapping_generate( &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_LOOP, cddata_type, mix_mode, mix_factor, weights[LDATA], num_loops_dst, use_create, use_delete, fromlayers, tolayers)) { CustomDataTransferLayerMap *lay_mapit; changed = (lay_map.first != NULL); for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) { CustomData_data_transfer(&geom_map[LDATA], lay_mapit); } BLI_freelistN(&lay_map); } } if (DT_DATATYPE_IS_POLY(dtdata_type)) { MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly; const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly; MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop; const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop; CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata; if (!geom_map_init[PDATA]) { const int num_polys_src = dm_src->getNumPolys(dm_src); if ((map_poly_mode == MREMAP_MODE_TOPOLOGY) && (num_polys_dst != num_polys_src)) { BKE_report(reports, RPT_ERROR, "Source and destination meshes do not have the same amount of faces, " "'Topology' mapping cannot be used in this case"); return changed; } if (ELEM(0, num_polys_dst, num_polys_src)) { BKE_report(reports, RPT_ERROR, "Source or destination meshes do not have any polygons, cannot transfer poly data"); return changed; } BKE_mesh_remap_calc_polys_from_dm( map_poly_mode, space_transform, max_distance, ray_radius, verts_dst, num_verts_dst, loops_dst, num_loops_dst, polys_dst, num_polys_dst, pdata_dst, dirty_nors_dst, dm_src, &geom_map[PDATA]); geom_map_init[PDATA] = true; } if (mdef && vg_idx != -1 && !weights[PDATA]) { weights[PDATA] = MEM_mallocN(sizeof(*weights[PDATA]) * (size_t)num_polys_dst, __func__); BKE_defvert_extract_vgroup_to_polyweights( mdef, vg_idx, num_verts_dst, loops_dst, num_loops_dst, polys_dst, num_polys_dst, weights[PDATA], invert_vgroup); } if (data_transfer_layersmapping_generate( &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_POLY, cddata_type, mix_mode, mix_factor, weights[PDATA], num_polys_dst, use_create, use_delete, fromlayers, tolayers)) { CustomDataTransferLayerMap *lay_mapit; changed = (lay_map.first != NULL); for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) { CustomData_data_transfer(&geom_map[PDATA], lay_mapit); } BLI_freelistN(&lay_map); } } data_transfer_dtdata_type_postprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst, dtdata_type, changed); } for (i = 0; i < DATAMAX; i++) { BKE_mesh_remap_free(&geom_map[i]); MEM_SAFE_FREE(weights[i]); } return changed; #undef VDATA #undef EDATA #undef LDATA #undef PDATA #undef DATAMAX }