diff --git a/release/scripts/ui/space_view3d.py b/release/scripts/ui/space_view3d.py index fa7cbe152de..e61394832da 100644 --- a/release/scripts/ui/space_view3d.py +++ b/release/scripts/ui/space_view3d.py @@ -603,6 +603,7 @@ class VIEW3D_MT_object(bpy.types.Menu): layout.separator() + layout.operator("object.join_shapes") layout.operator("object.join") layout.separator() diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 35e1f10b516..ba26104a555 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -83,6 +83,7 @@ int mesh_get_x_mirror_vert(struct Object *ob, int index); int *mesh_get_x_mirror_faces(struct Object *ob, struct EditMesh *em); int join_mesh_exec(struct bContext *C, struct wmOperator *op); +int join_mesh_shapes_exec(struct bContext *C, struct wmOperator *op); /* mesh_ops.c */ void ED_operatortypes_mesh(void); diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 5313b68be9b..02833bdf3f7 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -31,6 +31,7 @@ meshtools.c: no editmode (violated already :), tools operating on meshes */ +#include #include #include #include @@ -62,6 +63,7 @@ #include "BKE_blender.h" #include "BKE_context.h" #include "BKE_depsgraph.h" +#include "BKE_DerivedMesh.h" #include "BKE_customdata.h" #include "BKE_global.h" #include "BKE_image.h" @@ -543,6 +545,82 @@ int join_mesh_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +/*********************** JOIN AS SHAPES ***************************/ + +/* Append selected meshes vertex locations as shapes of the active mesh, + return 0 if no join is made (error) and 1 of the join is done */ + +int join_mesh_shapes_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Object *ob= CTX_data_active_object(C); + Mesh *me= (Mesh *)ob->data; + Mesh *selme=NULL; + DerivedMesh *dm=NULL; + Key *key=me->key; + KeyBlock *kb; + int ok=0, nonequal_verts=0; + + CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { + if (base->object == ob) continue; + + if (base->object->type==OB_MESH) { + selme = (Mesh *)base->object->data; + + if (selme->totvert==me->totvert) + ok++; + else + nonequal_verts=1; + } + } + CTX_DATA_END; + + if (!ok) { + if (nonequal_verts) + BKE_report(op->reports, RPT_ERROR, "Selected meshes must have equal numbers of vertices."); + else + BKE_report(op->reports, RPT_ERROR, "No additional selected meshes with equal vertex count to join."); + return OPERATOR_CANCELLED; + } + + if(key == NULL) { + key= me->key= add_key((ID *)me); + key->type= KEY_RELATIVE; + + /* first key added, so it was the basis. initialise it with the existing mesh */ + kb= add_keyblock(scene, key); + mesh_to_key(me, kb); + } + + /* now ready to add new keys from selected meshes */ + CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { + if (base->object == ob) continue; + + if(base->object->type==OB_MESH) { + selme = (Mesh *)base->object->data; + + if (selme->totvert==me->totvert) { + dm = mesh_get_derived_deform(scene, base->object, CD_MASK_BAREMESH); + + if (!dm) continue; + + kb= add_keyblock(scene, key); + strcpy(kb->name, base->object->id.name+2); + BLI_uniquename(&key->block, kb, "Key", '.', offsetof(KeyBlock, name), 32); + + DM_to_meshkey(dm, me, kb); + + dm->release(dm); + } + } + } + CTX_DATA_END; + + WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene); + + return OPERATOR_FINISHED; +} + /* ********************** SORT FACES ******************* */ static void permutate(void *list, int num, int size, int *index) diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index e3d2ef336fc..1cda61fe90f 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1506,6 +1506,18 @@ void OBJECT_OT_duplicate(wmOperatorType *ot) } /**************************** Join *************************/ +static int join_poll(bContext *C) +{ + Object *ob= CTX_data_active_object(C); + + if (!ob) return 0; + + if (ELEM4(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE)) + return ED_operator_screenactive(C); + else + return 0; +} + static int join_exec(bContext *C, wmOperator *op) { @@ -1516,10 +1528,6 @@ static int join_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_ERROR, "This data does not support joining in editmode."); return OPERATOR_CANCELLED; } - else if(!ob) { - BKE_report(op->reports, RPT_ERROR, "Can't join unless there is an active object."); - return OPERATOR_CANCELLED; - } else if(object_data_is_libdata(ob)) { BKE_report(op->reports, RPT_ERROR, "Can't edit external libdata."); return OPERATOR_CANCELLED; @@ -1531,9 +1539,7 @@ static int join_exec(bContext *C, wmOperator *op) return join_curve_exec(C, op); else if(ob->type == OB_ARMATURE) return join_armature_exec(C, op); - - BKE_report(op->reports, RPT_ERROR, "This object type doesn't support joining."); - + return OPERATOR_CANCELLED; } @@ -1546,9 +1552,57 @@ void OBJECT_OT_join(wmOperatorType *ot) /* api callbacks */ ot->exec= join_exec; - ot->poll= ED_operator_scene_editable; + ot->poll= join_poll; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; } +/**************************** Join as Shape Key*************************/ +static int join_shapes_poll(bContext *C) +{ + Object *ob= CTX_data_active_object(C); + + if (!ob) return 0; + + /* only meshes supported at the moment */ + if (ob->type == OB_MESH) + return ED_operator_screenactive(C); + else + return 0; +} + +static int join_shapes_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Object *ob= CTX_data_active_object(C); + + if(scene->obedit) { + BKE_report(op->reports, RPT_ERROR, "This data does not support joining in editmode."); + return OPERATOR_CANCELLED; + } + else if(object_data_is_libdata(ob)) { + BKE_report(op->reports, RPT_ERROR, "Can't edit external libdata."); + return OPERATOR_CANCELLED; + } + + if(ob->type == OB_MESH) + return join_mesh_shapes_exec(C, op); + + return OPERATOR_CANCELLED; +} + +void OBJECT_OT_join_shapes(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Join as Shapes"; + ot->description = "Merge selected objects to shapes of active object."; + ot->idname= "OBJECT_OT_join_shapes"; + + /* api callbacks */ + ot->exec= join_shapes_exec; + ot->poll= join_shapes_poll; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 046dd8939ba..9230dca7ba2 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -106,6 +106,7 @@ void OBJECT_OT_duplicates_make_real(struct wmOperatorType *ot); void OBJECT_OT_duplicate(struct wmOperatorType *ot); void OBJECT_OT_delete(struct wmOperatorType *ot); void OBJECT_OT_join(struct wmOperatorType *ot); +void OBJECT_OT_join_shapes(struct wmOperatorType *ot); void OBJECT_OT_convert(struct wmOperatorType *ot); /* object_hook.c */ diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 58f2ed443ca..7bb5eb6f63b 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -331,12 +331,104 @@ int ED_object_modifier_convert(ReportList *reports, Scene *scene, Object *ob, Mo return 1; } +static int modifier_apply_shape(ReportList *reports, Scene *scene, Object *ob, ModifierData *md) +{ + if (ob->type==OB_MESH) { + DerivedMesh *dm; + Mesh *me= ob->data; + Key *key=me->key; + KeyBlock *kb; + + if(!modifier_sameTopology(md)) { + BKE_report(reports, RPT_ERROR, "Only deforming modifiers can be applied to Shapes"); + return 0; + } + mesh_pmv_off(ob, me); + + dm = mesh_create_derived_for_modifier(scene, ob, md); + if (!dm) { + BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply"); + return 0; + } + + if(key == NULL) { + key= me->key= add_key((ID *)me); + key->type= KEY_RELATIVE; + /* if that was the first key block added, then it was the basis. + * Initialise it with the mesh, and add another for the modifier */ + kb= add_keyblock(scene, key); + mesh_to_key(me, kb); + } + + kb= add_keyblock(scene, key); + DM_to_meshkey(dm, me, kb); + + dm->release(dm); + } + else { + BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type"); + return 0; + } + return 1; +} + +static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob, ModifierData *md) +{ + if (ob->type==OB_MESH) { + DerivedMesh *dm; + Mesh *me = ob->data; + if( me->key) { + BKE_report(reports, RPT_ERROR, "Modifier cannot be applied to Mesh with Shape Keys"); + return 0; + } + + mesh_pmv_off(ob, me); + + /* Multires: ensure that recent sculpting is applied */ + if(md->type == eModifierType_Multires) + multires_force_update(ob); + + dm = mesh_create_derived_for_modifier(scene, ob, md); + if (!dm) { + BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply"); + return 0; + } + + DM_to_mesh(dm, me); + + dm->release(dm); + } + else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + Curve *cu = ob->data; + int numVerts; + float (*vertexCos)[3]; + + + BKE_report(reports, RPT_INFO, "Applied modifier only changed CV points, not tesselated/bevel vertices"); + + if (!(md->mode&eModifierMode_Realtime) || (mti->isDisabled && mti->isDisabled(md))) { + BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply"); + return 0; + } + + vertexCos = curve_getVertexCos(cu, &cu->nurb, &numVerts); + mti->deformVerts(md, ob, NULL, vertexCos, numVerts, 0, 0); + curve_applyVertexCos(cu, &cu->nurb, vertexCos); + + MEM_freeN(vertexCos); + + DAG_id_flush_update(&ob->id, OB_RECALC_DATA); + } + else { + BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type"); + return 0; + } + return 1; +} + int ED_object_modifier_apply(ReportList *reports, Scene *scene, Object *ob, ModifierData *md, int mode) { - DerivedMesh *dm; - Mesh *me = ob->data; - int converted = 0; - if (scene->obedit) { BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in editmode"); return 0; @@ -348,102 +440,18 @@ int ED_object_modifier_apply(ReportList *reports, Scene *scene, Object *ob, Modi if (md!=ob->modifiers.first) BKE_report(reports, RPT_INFO, "Applied modifier was not first, result may not be as expected."); - if (ob->type==OB_MESH) { - if (mode == MODIFIER_APPLY_SHAPE) { - Key *key=me->key; - KeyBlock *kb; - int newkey=0; - - if(!modifier_sameTopology(md)) { - BKE_report(reports, RPT_ERROR, "Only deforming modifiers can be applied to Shapes"); - return 0; - } - mesh_pmv_off(ob, me); - - dm = mesh_create_derived_for_modifier(scene, ob, md); - if (!dm) { - BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply"); - return 0; - } - - if(key == NULL) { - key= me->key= add_key((ID *)me); - key->type= KEY_RELATIVE; - newkey= 1; - } - kb= add_keyblock(scene, key); - - if (newkey) { - /* if that was the first key block added, then it was the basis. - * Initialise it with the mesh, and add another for the modifier */ - mesh_to_key(me, kb); - kb= add_keyblock(scene, key); - } - DM_to_meshkey(dm, me, kb); - converted = 1; - - dm->release(dm); - } - else { /* MODIFIER_APPLY_DATA */ - if( me->key) { - BKE_report(reports, RPT_ERROR, "Modifier cannot be applied to Mesh with Shape Keys"); - return 0; - } - - mesh_pmv_off(ob, me); - - /* Multires: ensure that recent sculpting is applied */ - if(md->type == eModifierType_Multires) - multires_force_update(ob); - - dm = mesh_create_derived_for_modifier(scene, ob, md); - if (!dm) { - BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply"); - return 0; - } - - DM_to_mesh(dm, me); - converted = 1; - - dm->release(dm); - } - } - else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); - Curve *cu = ob->data; - int numVerts; - float (*vertexCos)[3]; - - BKE_report(reports, RPT_INFO, "Applied modifier only changed CV points, not tesselated/bevel vertices"); - - if (!(md->mode&eModifierMode_Realtime) || (mti->isDisabled && mti->isDisabled(md))) { - BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply"); + if (mode == MODIFIER_APPLY_SHAPE) { + if (!modifier_apply_shape(reports, scene, ob, md)) + return 0; + } else { + if (!modifier_apply_obdata(reports, scene, ob, md)) return 0; - } - - vertexCos = curve_getVertexCos(cu, &cu->nurb, &numVerts); - mti->deformVerts(md, ob, NULL, vertexCos, numVerts, 0, 0); - curve_applyVertexCos(cu, &cu->nurb, vertexCos); - - converted = 1; - - MEM_freeN(vertexCos); - - DAG_id_flush_update(&ob->id, OB_RECALC_DATA); - } - else { - BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type"); - return 0; } - if (converted) { - BLI_remlink(&ob->modifiers, md); - modifier_free(md); + BLI_remlink(&ob->modifiers, md); + modifier_free(md); - return 1; - } - - return 0; + return 1; } int ED_object_modifier_copy(ReportList *reports, Object *ob, ModifierData *md) diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index c9a0b3f0614..edcd15492e8 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -124,6 +124,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_duplicates_make_real); WM_operatortype_append(OBJECT_OT_duplicate); WM_operatortype_append(OBJECT_OT_join); + WM_operatortype_append(OBJECT_OT_join_shapes); WM_operatortype_append(OBJECT_OT_convert); WM_operatortype_append(OBJECT_OT_modifier_add);