* New tool - Join as Shapes
authorMatt Ebb <matt@mke3.net>
Sat, 28 Nov 2009 04:04:01 +0000 (04:04 +0000)
committerMatt Ebb <matt@mke3.net>
Sat, 28 Nov 2009 04:04:01 +0000 (04:04 +0000)
Available in object mode (Object -> Join as Shapes), only works for meshes at
the present. Will merge all selected objects as shape keys on the active object,
if the vertex count is the same.

This does not keep references to the external objects like in some applications,
rather it's a quick way to update the shapes on the active object (perhaps after
importing new versions from external applications).

release/scripts/ui/space_view3d.py
source/blender/editors/include/ED_mesh.h
source/blender/editors/mesh/meshtools.c
source/blender/editors/object/object_add.c
source/blender/editors/object/object_intern.h
source/blender/editors/object/object_modifier.c
source/blender/editors/object/object_ops.c

index fa7cbe1..e613948 100644 (file)
@@ -603,6 +603,7 @@ class VIEW3D_MT_object(bpy.types.Menu):
 
         layout.separator()
 
+        layout.operator("object.join_shapes")
         layout.operator("object.join")
 
         layout.separator()
index 35e1f10..ba26104 100644 (file)
@@ -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);
index 5313b68..02833bd 100644 (file)
@@ -31,6 +31,7 @@
        meshtools.c: no editmode (violated already :), tools operating on meshes
 */
 
+#include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
@@ -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)
index e3d2ef3..1cda61f 100644 (file)
@@ -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;
+}
index 046dd89..9230dca 100644 (file)
@@ -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 */
index 58f2ed4..7bb5eb6 100644 (file)
@@ -331,119 +331,127 @@ int ED_object_modifier_convert(ReportList *reports, Scene *scene, Object *ob, Mo
        return 1;
 }
 
-int ED_object_modifier_apply(ReportList *reports, Scene *scene, Object *ob, ModifierData *md, int mode)
+static int modifier_apply_shape(ReportList *reports, Scene *scene, Object *ob, ModifierData *md)
 {
-       DerivedMesh *dm;
-       Mesh *me = ob->data;
-       int converted = 0;
+       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);
+               }
 
-       if (scene->obedit) {
-               BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in editmode");
-               return 0;
-       } else if (((ID*) ob->data)->us>1) {
-               BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data");
+               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;
+}
 
-       if (md!=ob->modifiers.first)
-               BKE_report(reports, RPT_INFO, "Applied modifier was not first, result may not be as expected.");
-
+static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob, ModifierData *md)
+{
        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);
+               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;
                }
-               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);
+               
+               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);
 
-               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;
        }
+       return 1;
+}
 
-       if (converted) {
-               BLI_remlink(&ob->modifiers, md);
-               modifier_free(md);
+int ED_object_modifier_apply(ReportList *reports, Scene *scene, Object *ob, ModifierData *md, int mode)
+{
+       if (scene->obedit) {
+               BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in editmode");
+               return 0;
+       } else if (((ID*) ob->data)->us>1) {
+               BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data");
+               return 0;
+       }
+
+       if (md!=ob->modifiers.first)
+               BKE_report(reports, RPT_INFO, "Applied modifier was not first, result may not be as expected.");
 
-               return 1;
+       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;
        }
 
-       return 0;
+       BLI_remlink(&ob->modifiers, md);
+       modifier_free(md);
+
+       return 1;
 }
 
 int ED_object_modifier_copy(ReportList *reports, Object *ob, ModifierData *md)
index c9a0b3f..edcd154 100644 (file)
@@ -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);