int BKE_object_data_transfer_get_dttypes_item_types(const int dtdata_types) { int i, ret = 0; for (i = 0; (i < DT_TYPE_MAX) && (ret ^ (ME_VERT | ME_EDGE | ME_LOOP | ME_POLY)); i++) { const int dtdata_type = 1 << i; if (!(dtdata_types & dtdata_type)) { continue; } if (DT_DATATYPE_IS_VERT(dtdata_type)) { ret |= ME_VERT; } if (DT_DATATYPE_IS_EDGE(dtdata_type)) { ret |= ME_EDGE; } if (DT_DATATYPE_IS_LOOP(dtdata_type)) { ret |= ME_LOOP; } if (DT_DATATYPE_IS_POLY(dtdata_type)) { ret |= ME_POLY; } } return ret; }
/* Used by both OBJECT_OT_data_transfer and OBJECT_OT_datalayout_transfer */ static bool data_transfer_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) { PropertyRNA *prop_other; const char *prop_id = RNA_property_identifier(prop); const int data_type = RNA_enum_get(ptr, "data_type"); bool use_auto_transform = false; bool use_max_distance = false; bool use_modifier = false; if ((prop_other = RNA_struct_find_property(ptr, "use_auto_transform"))) { use_auto_transform = RNA_property_boolean_get(ptr, prop_other); } if ((prop_other = RNA_struct_find_property(ptr, "use_max_distance"))) { use_max_distance = RNA_property_boolean_get(ptr, prop_other); } if ((prop_other = RNA_struct_find_property(ptr, "modifier"))) { use_modifier = RNA_property_is_set(ptr, prop_other); } if (STREQ(prop_id, "modifier")) { return use_modifier; } if (use_modifier) { /* Hide everything but 'modifier' property, if set. */ return false; } if (STREQ(prop_id, "use_object_transform") && use_auto_transform) { return false; } if (STREQ(prop_id, "max_distance") && !use_max_distance) { return false; } if (STREQ(prop_id, "islands_precision") && !DT_DATATYPE_IS_LOOP(data_type)) { return false; } if (STREQ(prop_id, "vert_mapping") && !DT_DATATYPE_IS_VERT(data_type)) { return false; } if (STREQ(prop_id, "edge_mapping") && !DT_DATATYPE_IS_EDGE(data_type)) { return false; } if (STREQ(prop_id, "loop_mapping") && !DT_DATATYPE_IS_LOOP(data_type)) { return false; } if (STREQ(prop_id, "poly_mapping") && !DT_DATATYPE_IS_POLY(data_type)) { return false; } if ((STREQ(prop_id, "layers_select_src") || STREQ(prop_id, "layers_select_dst")) && !DT_DATATYPE_IS_MULTILAYERS(data_type)) { return false; } /* Else, show it! */ return true; }
/** * 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); } } }
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 }