diff options
Diffstat (limited to 'source/blender/editors/object')
-rw-r--r-- | source/blender/editors/object/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/editors/object/object_data_transfer.c | 620 | ||||
-rw-r--r-- | source/blender/editors/object/object_intern.h | 4 | ||||
-rw-r--r-- | source/blender/editors/object/object_ops.c | 7 |
4 files changed, 632 insertions, 0 deletions
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt index 9b380ff8d48..79437bb05b9 100644 --- a/source/blender/editors/object/CMakeLists.txt +++ b/source/blender/editors/object/CMakeLists.txt @@ -56,6 +56,7 @@ set(SRC object_relations.c object_select.c object_shapekey.c + object_data_transfer.c object_transform.c object_warp.c object_vgroup.c diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c new file mode 100644 index 00000000000..1d994746ba6 --- /dev/null +++ b/source/blender/editors/object/object_data_transfer.c @@ -0,0 +1,620 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2014 by Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Bastien Montagne. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/object/object_transfer_data.c + * \ingroup edobj + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_object_data_transfer.h" +#include "BKE_DerivedMesh.h" +#include "BKE_mesh_mapping.h" +#include "BKE_mesh_remap.h" +#include "BKE_object.h" +#include "BKE_report.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_object.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "object_intern.h" + +/* All possible data to transfer. + * Note some are 'fake' ones, i.e. they are not hold by real CDLayers. */ +/* Not shared with modifier, since we use a usual enum here, not a multi-choice one. */ +static EnumPropertyItem DT_layer_items[] = { + {0, "", 0, "Vertex Data", ""}, + {DT_TYPE_MDEFORMVERT, "VGROUP_WEIGHTS", 0, "Vertex Group(s)", "Transfer active or all vertex groups"}, +#if 0 /* XXX For now, would like to finish/merge work from 2014 gsoc first. */ + {DT_TYPE_SHAPEKEY, "SHAPEKEYS", 0, "Shapekey(s)", "Transfer active or all shape keys"}, +#endif +#if 0 /* XXX When SkinModifier is enabled, it seems to erase its own CD_MVERT_SKIN layer from final DM :( */ + {DT_TYPE_SKIN, "SKIN", 0, "Skin Weight", "Transfer skin weights"}, +#endif + {DT_TYPE_BWEIGHT_VERT, "BEVEL_WEIGHT_VERT", 0, "Bevel Weight", "Transfer bevel weights"}, + {0, "", 0, "Edge Data", ""}, + {DT_TYPE_SHARP_EDGE, "SHARP_EDGE", 0, "Sharp", "Transfer sharp mark"}, + {DT_TYPE_SEAM, "SEAM", 0, "UV Seam", "Transfer UV seam mark"}, + {DT_TYPE_CREASE, "CREASE", 0, "Subsurf Crease", "Transfer crease values"}, + {DT_TYPE_BWEIGHT_EDGE, "BEVEL_WEIGHT_EDGE", 0, "Bevel Weight", "Transfer bevel weights"}, + {DT_TYPE_FREESTYLE_EDGE, "FREESTYLE_EDGE", 0, "Freestyle Mark", "Transfer Freestyle edge mark"}, + {0, "", 0, "Face Corner Data", ""}, + {DT_TYPE_VCOL, "VCOL", 0, "VCol", "Vertex (face corners) colors"}, + {DT_TYPE_UV, "UV", 0, "UVs", "Transfer UV layers"}, + {0, "", 0, "Face Data", ""}, + {DT_TYPE_SHARP_FACE, "SMOOTH", 0, "Smooth", "Transfer flat/smooth mark"}, + {DT_TYPE_FREESTYLE_FACE, "FREESTYLE_FACE", 0, "Freestyle Mark", "Transfer Freestyle face mark"}, + {0, NULL, 0, NULL, NULL} +}; + +/* Note: DT_layers_select_src_items enum is from rna_modifier.c */ +static EnumPropertyItem *dt_layers_select_src_itemf( + bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) +{ + EnumPropertyItem *item = NULL, tmp_item = {0}; + int totitem = 0; + + const int data_type = RNA_enum_get(ptr, "data_type"); + + if (!C) { /* needed for docs and i18n tools */ + return DT_layers_select_src_items; + } + + RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_ACTIVE_SRC); + RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_ALL_SRC); + + if (data_type == DT_TYPE_MDEFORMVERT) { + Object *ob_src = CTX_data_active_object(C); + + if (BKE_object_pose_armature_get(ob_src)) { + RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_SELECT); + RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_DEFORM); + } + + if (ob_src) { + bDeformGroup *dg; + int i; + + RNA_enum_item_add_separator(&item, &totitem); + + for (i = 0, dg = ob_src->defbase.first; dg; i++, dg = dg->next) { + tmp_item.value = i; + tmp_item.identifier = tmp_item.name = dg->name; + RNA_enum_item_add(&item, &totitem, &tmp_item); + } + } + } + else if (data_type == DT_TYPE_SHAPEKEY) { + /* TODO */ + } + else if (data_type == DT_TYPE_UV) { + Object *ob_src = CTX_data_active_object(C); + Scene *scene = CTX_data_scene(C); + + if (ob_src) { + DerivedMesh *dm_src; + CustomData *pdata; + int num_data, i; + + /* XXX Is this OK? */ + dm_src = mesh_get_derived_final(scene, ob_src, CD_MASK_BAREMESH | CD_MTEXPOLY); + pdata = dm_src->getPolyDataLayout(dm_src); + num_data = CustomData_number_of_layers(pdata, CD_MTEXPOLY); + + RNA_enum_item_add_separator(&item, &totitem); + + for (i = 0; i < num_data; i++) { + tmp_item.value = i; + tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(pdata, CD_MTEXPOLY, i); + RNA_enum_item_add(&item, &totitem, &tmp_item); + } + } + } + else if (data_type == DT_TYPE_VCOL) { + Object *ob_src = CTX_data_active_object(C); + Scene *scene = CTX_data_scene(C); + + if (ob_src) { + DerivedMesh *dm_src; + CustomData *ldata; + int num_data, i; + + /* XXX Is this OK? */ + dm_src = mesh_get_derived_final(scene, ob_src, CD_MASK_BAREMESH | CD_MLOOPCOL); + ldata = dm_src->getLoopDataLayout(dm_src); + num_data = CustomData_number_of_layers(ldata, CD_MLOOPCOL); + + RNA_enum_item_add_separator(&item, &totitem); + + for (i = 0; i < num_data; i++) { + tmp_item.value = i; + tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(ldata, CD_MLOOPCOL, i); + RNA_enum_item_add(&item, &totitem, &tmp_item); + } + } + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + +/* Note: DT_layers_select_dst_items enum is from rna_modifier.c */ +static EnumPropertyItem *dt_layers_select_dst_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) +{ + EnumPropertyItem *item = NULL; + int totitem = 0; + + const int layers_select_src = RNA_enum_get(ptr, "layers_select_src"); + + if (!C) { /* needed for docs and i18n tools */ + return DT_layers_select_dst_items; + } + + if (layers_select_src == DT_LAYERS_ACTIVE_SRC || layers_select_src >= 0) { + RNA_enum_items_add_value(&item, &totitem, DT_layers_select_dst_items, DT_LAYERS_ACTIVE_DST); + } + RNA_enum_items_add_value(&item, &totitem, DT_layers_select_dst_items, DT_LAYERS_NAME_DST); + RNA_enum_items_add_value(&item, &totitem, DT_layers_select_dst_items, DT_LAYERS_INDEX_DST); + + /* No 'specific' to-layers here, since we may transfer to several objects at once! */ + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + +/* Note: DT_mix_mode_items enum is from rna_modifier.c */ +static EnumPropertyItem *dt_mix_mode_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) +{ + EnumPropertyItem *item = NULL; + int totitem = 0; + + const int dtdata_type = RNA_enum_get(ptr, "data_type"); + bool support_advanced_mixing, support_threshold; + + if (!C) { /* needed for docs and i18n tools */ + return DT_mix_mode_items; + } + + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_TRANSFER); + + BKE_object_data_transfer_get_dttypes_capacity(dtdata_type, &support_advanced_mixing, &support_threshold); + + if (support_advanced_mixing) { + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_REPLACE_ABOVE_THRESHOLD); + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_REPLACE_BELOW_THRESHOLD); + } + + if (support_advanced_mixing) { + RNA_enum_item_add_separator(&item, &totitem); + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_MIX); + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_ADD); + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_SUB); + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_MUL); + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + +static bool data_transfer_check(bContext *UNUSED(C), wmOperator *op) +{ + const int layers_select_src = RNA_enum_get(op->ptr, "layers_select_src"); + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "layers_select_dst"); + const int layers_select_dst = RNA_property_enum_get(op->ptr, prop); + + /* TODO: check for invalid layers_src select modes too! */ + + if ((layers_select_src != DT_LAYERS_ACTIVE_SRC) && (layers_select_dst == DT_LAYERS_ACTIVE_DST)) { + RNA_property_enum_set(op->ptr, prop, DT_LAYERS_NAME_DST); + return true; + } + + return false; +} + +/* Helper, used by both data_transfer_exec and datalayout_transfer_exec. */ +static void data_transfer_exec_preprocess_objects(bContext *C, wmOperator *op, Object *ob_src, ListBase *ctx_objects) +{ + CollectionPointerLink *ctx_ob; + CTX_data_selected_editable_objects(C, ctx_objects); + + for (ctx_ob = ctx_objects->first; ctx_ob; ctx_ob = ctx_ob->next) { + Object *ob = ctx_ob->ptr.data; + Mesh *me; + if ((ob == ob_src) || (ob->type != OB_MESH)) { + continue; + } + + me = ob->data; + if (me->id.lib) { + /* Do not transfer to linked data, not supported. */ + BKE_reportf(op->reports, RPT_WARNING, "Skipping object '%s', linked data '%s' cannot be modified", + ob->id.name + 2, me->id.name + 2); + me->id.flag &= ~LIB_DOIT; + continue; + } + + me->id.flag |= LIB_DOIT; + } +} + +/* Helper, used by both data_transfer_exec and datalayout_transfer_exec. */ +static bool data_transfer_exec_is_object_valid(wmOperator *op, Object *ob_src, Object *ob_dst) +{ + Mesh *me; + if ((ob_dst == ob_src) || (ob_dst->type != OB_MESH)) { + return false; + } + + me = ob_dst->data; + if (me->id.flag & LIB_DOIT) { + me->id.flag &= ~LIB_DOIT; + return true; + } + else if (me->id.lib == NULL) { + /* Do not transfer apply operation more than once. */ + /* XXX This is not nice regarding vgroups, which are half-Object data... :/ */ + BKE_reportf(op->reports, RPT_WARNING, + "Skipping object '%s', data '%s' has already been processed with a previous object", + ob_dst->id.name + 2, me->id.name + 2); + } + return false; +} + +static int data_transfer_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Object *ob_src = CTX_data_active_object(C); + + ListBase ctx_objects; + CollectionPointerLink *ctx_ob_dst; + + bool changed = false; + + 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_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 ? &space_transform_data : NULL; + + 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); + + 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)) { + 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, max_distance, ray_radius, islands_precision, + layers_select_src, layers_select_dst, + mix_mode, mix_factor, NULL, false, op->reports)) + { + changed = true; + } + } + } + + BLI_freelistN(&ctx_objects); + +#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 + return OPERATOR_FINISHED; +#endif +} + +/* Used by both OBJECT_OT_data_transfer and OBJECT_OT_datalayout_transfer */ +static int data_transfer_poll(bContext *C) +{ + Object *ob = ED_object_context(C); + ID *data = (ob) ? ob->data : NULL; + return (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib); +} + +/* 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_max_distance = false; + bool use_modifier = false; + + 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, "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; +} + +/* Used by both OBJECT_OT_data_transfer and OBJECT_OT_datalayout_transfer */ +static void data_transfer_ui(bContext *C, wmOperator *op) +{ + uiLayout *layout = op->layout; + wmWindowManager *wm = CTX_wm_manager(C); + PointerRNA ptr; + + RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); + + /* Main auto-draw call */ + uiDefAutoButsRNA(layout, &ptr, data_transfer_draw_check_prop, '\0'); +} + +/* transfers weight from active to selected */ +void OBJECT_OT_data_transfer(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* Identifiers.*/ + ot->name = "Transfer Mesh Data"; + ot->idname = "OBJECT_OT_data_transfer"; + ot->description = "Transfer data layer(s) (weights, edge sharp, ...) from active to selected meshes"; + + /* API callbacks.*/ + ot->poll = data_transfer_poll; + ot->invoke = WM_menu_invoke; + ot->exec = data_transfer_exec; + ot->check = data_transfer_check; + ot->ui = data_transfer_ui; + + /* Flags.*/ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* Properties.*/ + /* Data type to transfer. */ + ot->prop = RNA_def_enum(ot->srna, "data_type", DT_layer_items, 0, "Data Type", "Which data to transfer"); + RNA_def_boolean(ot->srna, "use_create", true, "Create Data", "Add data layers on destination meshes if needed"); + + /* Mapping methods. */ + RNA_def_enum(ot->srna, "vert_mapping", DT_method_vertex_items, MREMAP_MODE_VERT_NEAREST, "Vertex Mapping", + "Method used to map source vertices to destination ones"); + RNA_def_enum(ot->srna, "edge_mapping", DT_method_edge_items, MREMAP_MODE_EDGE_NEAREST, "Edge Mapping", + "Method used to map source edges to destination ones"); + RNA_def_enum(ot->srna, "loop_mapping", DT_method_loop_items, MREMAP_MODE_LOOP_NEAREST_POLYNOR, + "Face Corner Mapping", "Method used to map source faces' corners to destination ones"); + RNA_def_enum(ot->srna, "poly_mapping", DT_method_poly_items, MREMAP_MODE_POLY_NEAREST, "Face Mapping", + "Method used to map source faces to destination ones"); + + /* Mapping options and filtering. */ + RNA_def_boolean(ot->srna, "use_object_transform", true, "Object Transform", + "Evaluate source and destination meshes in their respective object spaces"); + RNA_def_boolean(ot->srna, "use_max_distance", false, "Only Neighbor Geometry", + "Source elements must be closer than given distance from destination one"); + prop = RNA_def_float(ot->srna, "max_distance", 1.0f, 0.0f, FLT_MAX, "Max Distance", + "Maximum allowed distance between source and destination element, for non-topology mappings", + 0.0f, 100.0f); + RNA_def_property_subtype(prop, PROP_DISTANCE); + prop = RNA_def_float(ot->srna, "ray_radius", 0.0f, 0.0f, FLT_MAX, "Ray Radius", + "'Width' of rays (especially useful when raycasting against vertices or edges)", + 0.0f, 10.0f); + RNA_def_property_subtype(prop, PROP_DISTANCE); + prop = RNA_def_float(ot->srna, "islands_precision", 0.1f, 0.0f, 10.0f, "Islands Precision", + "Factor controlling precision of islands handling (the higher, the better the results)", + 0.0f, 1.0f); + RNA_def_property_subtype(prop, PROP_FACTOR); + + /* How to handle multi-layers types of data. */ + prop = RNA_def_enum(ot->srna, "layers_select_src", DT_layers_select_src_items, DT_LAYERS_ACTIVE_SRC, + "Source Layers Selection", "Which layers to transfer, in case of multi-layers types"); + RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_src_itemf); + + prop = RNA_def_enum(ot->srna, "layers_select_dst", DT_layers_select_dst_items, DT_LAYERS_ACTIVE_DST, + "Destination Layers Matching", "How to match source and destination layers"); + RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_dst_itemf); + + prop = RNA_def_enum(ot->srna, "mix_mode", DT_mix_mode_items, CDT_MIX_TRANSFER, "Mix Mode", + "How to affect destination elements with source values"); + RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_mix_mode_itemf); + RNA_def_float(ot->srna, "mix_factor", 1.0f, 0.0f, 1.0f, "Mix Factor", + "Factor to use when applying data to destination (exact behavior depends on mix mode)", 0.0f, 1.0f); +} + +/******************************************************************************/ +/* Note: This operator is hybrid, it can work as a usual standalone Object operator, + * or as a DataTransfer modifier tool. + */ + +static int datalayout_transfer_poll(bContext *C) +{ + return (data_transfer_poll(C)); +} + +static int datalayout_transfer_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Object *ob_act = ED_object_active_context(C); + + { + 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); + + 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)) { + BKE_object_data_transfer_layout(scene, ob_src, ob_dst, data_type, use_delete, + layers_select_src, layers_select_dst); + } + } + + BLI_freelistN(&ctx_objects); + } + + return OPERATOR_FINISHED; +} + +static int datalayout_transfer_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + return WM_menu_invoke(C, op, event); +} + +void OBJECT_OT_datalayout_transfer(wmOperatorType *ot) +{ + PropertyRNA *prop; + + ot->name = "Transfer Mesh Datalayout"; + ot->description = "Transfer layout of data layer(s) from active to selected meshes"; + ot->idname = "OBJECT_OT_datalayout_transfer"; + + ot->poll = datalayout_transfer_poll; + ot->invoke = datalayout_transfer_invoke; + ot->exec = datalayout_transfer_exec; + ot->check = data_transfer_check; + ot->ui = data_transfer_ui; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* Properties.*/ + /* edit_modifier_properties(ot); */ + + /* Data type to transfer. */ + ot->prop = RNA_def_enum(ot->srna, "data_type", DT_layer_items, 0, "Data Type", "Which data to transfer"); + RNA_def_boolean(ot->srna, "use_delete", false, "Exact Match", + "Also delete some data layers from destination if necessary, so that it matches exactly source"); + + /* How to handle multi-layers types of data. */ + prop = RNA_def_enum(ot->srna, "layers_select_src", DT_layers_select_src_items, DT_LAYERS_ACTIVE_SRC, + "Source Layers Selection", "Which layers to transfer, in case of multi-layers types"); + RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_src_itemf); + + prop = RNA_def_enum(ot->srna, "layers_select_dst", DT_layers_select_dst_items, DT_LAYERS_ACTIVE_DST, + "Destination Layers Matching", "How to match source and destination layers"); + RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_dst_itemf); +} diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 6fa3caa6172..bcf77d819fe 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -266,5 +266,9 @@ void OBJECT_OT_lod_remove(struct wmOperatorType *ot); /* object_random.c */ void OBJECT_OT_vertex_random(struct wmOperatorType *ot); +/* object_transfer_data.c */ +void OBJECT_OT_data_transfer(struct wmOperatorType *ot); +void OBJECT_OT_datalayout_transfer(struct wmOperatorType *ot); + #endif /* __OBJECT_INTERN_H__ */ diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 2062b85fe4b..5189594c919 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -249,6 +249,9 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_lod_remove); WM_operatortype_append(OBJECT_OT_vertex_random); + + WM_operatortype_append(OBJECT_OT_data_transfer); + WM_operatortype_append(OBJECT_OT_datalayout_transfer); } void ED_operatormacros_object(void) @@ -420,6 +423,10 @@ void ED_keymap_object(wmKeyConfig *keyconf) WM_keymap_add_menu(keymap, "VIEW3D_MT_object_specials", WKEY, KM_PRESS, 0, 0); + WM_keymap_verify_item(keymap, "OBJECT_OT_data_transfer", TKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); + /* XXX No more available 'T' shortcuts... :/ */ + /* WM_keymap_verify_item(keymap, "OBJECT_OT_datalayout_transfer", TKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); */ + for (i = 0; i <= 5; i++) { kmi = WM_keymap_add_item(keymap, "OBJECT_OT_subdivision_set", ZEROKEY + i, KM_PRESS, KM_CTRL, 0); RNA_int_set(kmi->ptr, "level", i); |