Add operator to extract armature and vertex groups from skin.
authorNicholas Bishop <nicholasbishop@gmail.com>
Tue, 22 May 2012 15:29:57 +0000 (15:29 +0000)
committerNicholas Bishop <nicholasbishop@gmail.com>
Tue, 22 May 2012 15:29:57 +0000 (15:29 +0000)
* The operator creates bones for each input edge (does not subdivide
  them like the skin operator does), adds a fake root bone for skin
  roots with multiple children.

* The operator adds vertex weight groups to the original mesh.

* Make copy_object_transform() public, used to match the armature
  object to the mesh object.

Skin modifier documentation:
http://wiki.blender.org/index.php/User:Nicholasbishop/SkinModifier

source/blender/blenkernel/BKE_object.h
source/blender/blenkernel/intern/customdata.c
source/blender/blenkernel/intern/object.c
source/blender/editors/object/object_intern.h
source/blender/editors/object/object_modifier.c
source/blender/editors/object/object_ops.c

index 1cdf2ee..890fc40 100644 (file)
@@ -53,6 +53,7 @@ struct MovieClip;
 void BKE_object_workob_clear(struct Object *workob);
 void BKE_object_workob_calc_parent(struct Scene *scene, struct Object *ob, struct Object *workob);
 
+void BKE_object_transform_copy(struct Object *ob_tar, const struct Object *ob_src);
 struct SoftBody *copy_softbody(struct SoftBody *sb);
 struct BulletSoftBody *copy_bulletsoftbody(struct BulletSoftBody *sb);
 void BKE_object_copy_particlesystems(struct Object *obn, struct Object *ob);
index 645267f..04bce0a 100644 (file)
@@ -1168,7 +1168,7 @@ const CustomDataMask CD_MASK_DERIVEDMESH =
     CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_PREVIEW_MLOOPCOL |
     CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORIGSPACE_MLOOP | CD_MASK_ORCO | CD_MASK_TANGENT |
     CD_MASK_PREVIEW_MCOL | CD_MASK_NORMAL | CD_MASK_SHAPEKEY | CD_MASK_RECAST |
-    CD_MASK_ORIGINDEX | CD_MASK_POLYINDEX;
+    CD_MASK_ORIGINDEX | CD_MASK_POLYINDEX | CD_MASK_MVERT_SKIN;
 const CustomDataMask CD_MASK_BMESH =
     CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY |
     CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT |
index 6f6881c..8de832e 100644 (file)
@@ -1090,7 +1090,7 @@ Object *BKE_object_pose_armature_get(Object *ob)
        return NULL;
 }
 
-static void copy_object_transform(Object *ob_tar, Object *ob_src)
+void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src)
 {
        copy_v3_v3(ob_tar->loc, ob_src->loc);
        copy_v3_v3(ob_tar->rot, ob_src->rot);
@@ -1365,7 +1365,7 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
                BKE_object_apply_mat4(ob, ob->obmat, FALSE, TRUE);
        }
        else {
-               copy_object_transform(ob, target);
+               BKE_object_transform_copy(ob, target);
                ob->parent = target->parent; /* libdata */
                copy_m4_m4(ob->parentinv, target->parentinv);
        }
index 2bd53a3..4b33c56 100644 (file)
@@ -163,6 +163,7 @@ void OBJECT_OT_ocean_bake(struct wmOperatorType *ot);
 void OBJECT_OT_skin_root_mark(struct wmOperatorType *ot);
 void OBJECT_OT_skin_loose_mark_clear(struct wmOperatorType *ot);
 void OBJECT_OT_skin_radii_equalize(struct wmOperatorType *ot);
+void OBJECT_OT_skin_armature_create(struct wmOperatorType *ot);
 
 /* object_constraint.c */
 void OBJECT_OT_constraint_add(struct wmOperatorType *ot);
index e98ff4a..e13e15e 100644 (file)
@@ -35,6 +35,7 @@
 #include "MEM_guardedalloc.h"
 
 #include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
 #include "DNA_curve_types.h"
 #include "DNA_key_types.h"
 #include "DNA_mesh_types.h"
@@ -42,6 +43,7 @@
 #include "DNA_object_force.h"
 #include "DNA_scene_types.h"
 
+#include "BLI_bitmap.h"
 #include "BLI_math.h"
 #include "BLI_listbase.h"
 #include "BLI_string.h"
@@ -1367,6 +1369,12 @@ static void modifier_skin_customdata_ensure(Object *ob)
        }
 }
 
+static int skin_poll(bContext *C)
+{
+       return (!CTX_data_edit_object(C) &&
+                       edit_modifier_poll_generic(C, &RNA_SkinModifier, (1<<OB_MESH)));
+}
+
 static int skin_edit_poll(bContext *C)
 {
        return (CTX_data_edit_object(C) &&
@@ -1542,6 +1550,192 @@ void OBJECT_OT_skin_radii_equalize(wmOperatorType *ot)
        ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
+static void skin_armature_bone_create(Object *skin_ob,
+                                                                         MVert *mvert, MEdge *medge,
+                                                                         bArmature *arm,
+                                                                         BLI_bitmap edges_visited,
+                                                                         const MeshElemMap *emap,
+                                                                         EditBone *parent_bone,
+                                                                         int parent_v)
+{
+       int i;
+
+       for(i = 0; i < emap[parent_v].count; i++) {
+               int endx = emap[parent_v].indices[i];
+               const MEdge *e = &medge[endx];
+               EditBone *bone;
+               bDeformGroup *dg;
+               int v;
+
+               /* ignore edge if already visited */
+               if(BLI_BITMAP_GET(edges_visited, endx))
+                       continue;
+               BLI_BITMAP_SET(edges_visited, endx);
+
+               v = (e->v1 == parent_v ? e->v2 : e->v1);
+
+               bone = MEM_callocN(sizeof(EditBone),
+                                                  "skin_armature_bone_create EditBone");
+
+               bone->parent = parent_bone;
+               bone->layer = 1;
+               bone->flag |= BONE_CONNECTED;
+
+               copy_v3_v3(bone->head, mvert[parent_v].co);
+               copy_v3_v3(bone->tail, mvert[v].co);
+               bone->rad_head = bone->rad_tail = 0.25;
+               BLI_snprintf(bone->name, sizeof(bone->name), "Bone.%.2d", endx);
+
+               BLI_addtail(arm->edbo, bone);
+
+               /* add bDeformGroup */
+               if((dg = ED_vgroup_add_name(skin_ob, bone->name))) {
+                       ED_vgroup_vert_add(skin_ob, dg, parent_v, 1, WEIGHT_REPLACE);
+                       ED_vgroup_vert_add(skin_ob, dg, v, 1, WEIGHT_REPLACE);
+               }
+               
+               skin_armature_bone_create(skin_ob,
+                                                                 mvert, medge,
+                                                                 arm,
+                                                                 edges_visited,
+                                                                 emap,
+                                                                 bone,
+                                                                 v);
+       }
+}
+
+static Object *modifier_skin_armature_create(struct Scene *scene,
+                                                                                        Object *skin_ob)
+{
+       BLI_bitmap edges_visited;
+       DerivedMesh *deform_dm;
+       MVert *mvert;
+       Mesh *me = skin_ob->data;
+       Object *arm_ob;
+       bArmature *arm;
+       MVertSkin *mvert_skin;
+       MeshElemMap *emap;
+       int *emap_mem;
+       int v;
+
+       deform_dm = mesh_get_derived_deform(scene, skin_ob, CD_MASK_BAREMESH);
+       mvert = deform_dm->getVertArray(deform_dm);
+
+       /* add vertex weights to original mesh */
+       CustomData_add_layer(&me->vdata,
+                                                CD_MDEFORMVERT,
+                                                CD_CALLOC,
+                                                NULL,
+                                                me->totvert);
+       
+       arm_ob = BKE_object_add(scene, OB_ARMATURE);
+       BKE_object_transform_copy(arm_ob, skin_ob);
+       arm = arm_ob->data;
+       arm->layer = 1;
+       arm_ob->dtx |= OB_DRAWXRAY;
+       arm->drawtype = ARM_LINE;
+       arm->edbo = MEM_callocN(sizeof(ListBase), "edbo armature");
+
+       mvert_skin = CustomData_get_layer(&me->vdata, CD_MVERT_SKIN);
+       create_vert_edge_map(&emap, &emap_mem,
+                                                me->medge, me->totvert, me->totedge);
+
+       edges_visited = BLI_BITMAP_NEW(me->totedge, "edge_visited");
+
+       /* note: we use EditBones here, easier to set them up and use
+        * edit-armature functions to convert back to regular bones */
+       for(v = 0; v < me->totvert; v++) {
+               if(mvert_skin[v].flag & MVERT_SKIN_ROOT) {
+                       EditBone *bone = NULL;
+
+                       /* Unless the skin root has just one adjacent edge, create
+                          a fake root bone (have it going off in the Y direction
+                          (arbitrary) */
+                       if (emap[v].count > 1) {
+                               bone = MEM_callocN(sizeof(EditBone), "EditBone");
+
+                               copy_v3_v3(bone->head, me->mvert[v].co);
+                               copy_v3_v3(bone->tail, me->mvert[v].co);
+                               bone->layer = 1;
+
+                               bone->head[1] = 1.0f;
+                               bone->rad_head = bone->rad_tail = 0.25;
+
+                               BLI_addtail(arm->edbo, bone);
+                       }
+                       
+                       if(emap[v].count >= 1) {
+                               skin_armature_bone_create(skin_ob,
+                                                                                 mvert, me->medge,
+                                                                                 arm,
+                                                                                 edges_visited,
+                                                                                 emap,
+                                                                                 bone,
+                                                                                 v);
+                       }
+               }
+       }
+
+       MEM_freeN(edges_visited);
+       MEM_freeN(emap);
+       MEM_freeN(emap_mem);
+
+       ED_armature_from_edit(arm_ob);
+       ED_armature_edit_free(arm_ob);
+
+       return arm_ob;
+}
+
+static int skin_armature_create_exec(bContext *C, wmOperator *op)
+{
+       Main *bmain = CTX_data_main(C);
+       Scene *scene = CTX_data_scene(C);
+       Object *ob = CTX_data_active_object(C), *arm_ob;
+       ModifierData *skin_md;
+       ArmatureModifierData *arm_md;
+
+       /* create new armature */
+       arm_ob = modifier_skin_armature_create(scene, ob);
+
+       /* add a modifier to connect the new armature to the mesh */
+       arm_md= (ArmatureModifierData*)modifier_new(eModifierType_Armature);
+       if (arm_md) {
+               skin_md = edit_modifier_property_get(op, ob, eModifierType_Skin);
+               BLI_insertlinkafter(&ob->modifiers, skin_md, arm_md);
+
+               arm_md->object = arm_ob;
+               arm_md->deformflag = ARM_DEF_VGROUP | ARM_DEF_QUATERNION;
+               DAG_scene_sort(bmain, scene);
+               DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+       }
+
+       WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
+
+       return OPERATOR_FINISHED;
+}
+
+static int skin_armature_create_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+{
+       if (edit_modifier_invoke_properties(C, op))
+               return skin_armature_create_exec(C, op);
+       else
+               return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_skin_armature_create(wmOperatorType *ot)
+{
+       ot->name = "Skin Armature Create";
+       ot->description = "Create an armature that parallels the skin layout";
+       ot->idname = "OBJECT_OT_skin_armature_create";
+
+       ot->poll = skin_poll;
+       ot->invoke = skin_armature_create_invoke;
+       ot->exec = skin_armature_create_exec;
+       
+       /* flags */
+       ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+       edit_modifier_properties(ot);
+}
 
 /************************ mdef bind operator *********************/
 
index 1f09d8f..01f6b64 100644 (file)
@@ -142,6 +142,8 @@ void ED_operatortypes_object(void)
        WM_operatortype_append(OBJECT_OT_skin_root_mark);
        WM_operatortype_append(OBJECT_OT_skin_loose_mark_clear);
        WM_operatortype_append(OBJECT_OT_skin_radii_equalize);
+       WM_operatortype_append(OBJECT_OT_skin_armature_create);
+
        WM_operatortype_append(OBJECT_OT_meshdeform_bind);
        WM_operatortype_append(OBJECT_OT_explode_refresh);
        WM_operatortype_append(OBJECT_OT_ocean_bake);