/* separate selected bones into their armature */ static int separate_armature_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); Object *oldob, *newob; Base *oldbase, *newbase; /* sanity checks */ if (obedit == NULL) return OPERATOR_CANCELLED; /* set wait cursor in case this takes a while */ WM_cursor_wait(1); /* we are going to do this as follows (unlike every other instance of separate): * 1. exit editmode +posemode for active armature/base. Take note of what this is. * 2. duplicate base - BASACT is the new one now * 3. for each of the two armatures, enter editmode -> remove appropriate bones -> exit editmode + recalc * 4. fix constraint links * 5. make original armature active and enter editmode */ /* 1) only edit-base selected */ /* TODO: use context iterators for this? */ CTX_DATA_BEGIN(C, Base *, base, visible_bases) { if (base->object == obedit) base->flag |= 1; else base->flag &= ~1; } CTX_DATA_END; /* 1) store starting settings and exit editmode */ oldob = obedit; oldbase = BASACT; oldob->mode &= ~OB_MODE_POSE; //oldbase->flag &= ~OB_POSEMODE; ED_armature_from_edit(obedit); ED_armature_edit_free(obedit); /* 2) duplicate base */ newbase = ED_object_add_duplicate(bmain, scene, oldbase, USER_DUP_ARM); /* only duplicate linked armature */ DAG_relations_tag_update(bmain); newob = newbase->object; newbase->flag &= ~SELECT; /* 3) remove bones that shouldn't still be around on both armatures */ separate_armature_bones(oldob, 1); separate_armature_bones(newob, 0); /* 4) fix links before depsgraph flushes */ // err... or after? separated_armature_fix_links(oldob, newob); DAG_id_tag_update(&oldob->id, OB_RECALC_DATA); /* this is the original one */ DAG_id_tag_update(&newob->id, OB_RECALC_DATA); /* this is the separated one */ /* 5) restore original conditions */ obedit = oldob; ED_armature_to_edit(obedit); /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit); /* recalc/redraw + cleanup */ WM_cursor_wait(0); return OPERATOR_FINISHED; }
/* return 1: success */ static int mesh_separate_selected(wmOperator *op, Main *bmain, Scene *scene, Base *editbase) { EditMesh *em, *emnew; EditVert *eve, *v1; EditEdge *eed, *e1; EditFace *efa, *f1; Object *obedit; Mesh *me, *menew; Base *basenew; if(editbase==NULL) return 0; obedit= editbase->object; me= obedit->data; em= BKE_mesh_get_editmesh(me); if(me->key) { BKE_report(op->reports, RPT_WARNING, "Can't separate mesh with shape keys"); BKE_mesh_end_editmesh(me, em); return 0; } if(em->selected.first) BLI_freelistN(&(em->selected)); /* clear the selection order */ EM_selectmode_set(em); // enforce full consistent selection flags EM_stats_update(em); if(em->totvertsel==0) { BKE_mesh_end_editmesh(me, em); return 0; } /* we are going to work as follows: * 1. add a linked duplicate object: this will be the new one, we remember old pointer * 2. give new object empty mesh and put in editmode * 3: do a split if needed on current editmesh. * 4. copy over: all NOT selected verts, edges, faces * 5. call load_editMesh() on the new object */ /* 1 */ basenew= ED_object_add_duplicate(bmain, scene, editbase, 0); /* 0 = fully linked */ ED_base_object_select(basenew, BA_DESELECT); /* 2 */ basenew->object->data= menew= add_mesh(me->id.name+2); /* empty */ assign_matarar(basenew->object, give_matarar(obedit), *give_totcolp(obedit)); /* new in 2.5 */ me->id.us--; make_editMesh(scene, basenew->object); emnew= menew->edit_mesh; CustomData_copy(&em->vdata, &emnew->vdata, CD_MASK_EDITMESH, CD_DEFAULT, 0); CustomData_copy(&em->edata, &emnew->edata, CD_MASK_EDITMESH, CD_DEFAULT, 0); CustomData_copy(&em->fdata, &emnew->fdata, CD_MASK_EDITMESH, CD_DEFAULT, 0); /* 3 */ /* SPLIT: first make duplicate */ adduplicateflag(em, SELECT); /* SPLIT: old faces have 3x flag 128 set, delete these ones */ delfaceflag(em, 128); /* since we do tricky things with verts/edges/faces, this makes sure all is selected coherent */ EM_selectmode_set(em); /* 4 */ /* move over: everything that is selected */ for(eve= em->verts.first; eve; eve= v1) { v1= eve->next; if(eve->f & SELECT) { BLI_remlink(&em->verts, eve); BLI_addtail(&emnew->verts, eve); } } for(eed= em->edges.first; eed; eed= e1) { e1= eed->next; if(eed->f & SELECT) { BLI_remlink(&em->edges, eed); BLI_addtail(&emnew->edges, eed); } } for(efa= em->faces.first; efa; efa= f1) { f1= efa->next; if (efa == em->act_face && (efa->f & SELECT)) { EM_set_actFace(em, NULL); } if(efa->f & SELECT) { BLI_remlink(&em->faces, efa); BLI_addtail(&emnew->faces, efa); } } /* 5 */ load_editMesh(scene, basenew->object); free_editMesh(emnew); MEM_freeN(menew->edit_mesh); menew->edit_mesh= NULL; /* copy settings */ menew->texflag= me->texflag; menew->drawflag= me->drawflag; menew->flag= me->flag; menew->editflag= me->editflag; menew->smoothresh= me->smoothresh; /* hashedges are invalid now, make new! */ editMesh_set_hash(em); DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); DAG_id_tag_update(&basenew->object->id, OB_RECALC_DATA); BKE_mesh_end_editmesh(me, em); return 1; }