void ED_armature_apply_transform(Object *ob, float mat[4][4]) { bArmature *arm = ob->data; /* Put the armature into editmode */ ED_armature_to_edit(arm); /* Transform the bones */ ED_armature_transform_bones(arm, mat); /* Turn the list into an armature */ ED_armature_from_edit(arm); ED_armature_edit_free(arm); }
/* Helper function for armature separating - remove certain bones from the given armature * sel: remove selected bones from the armature, otherwise the unselected bones are removed * (ob is not in editmode) */ static void separate_armature_bones(Object *ob, short sel) { bArmature *arm = (bArmature *)ob->data; bPoseChannel *pchan, *pchann; EditBone *curbone; /* make local set of editbones to manipulate here */ ED_armature_to_edit(ob); /* go through pose-channels, checking if a bone should be removed */ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchann) { pchann = pchan->next; curbone = editbone_name_exists(arm->edbo, pchan->name); /* check if bone needs to be removed */ if ( (sel && (curbone->flag & BONE_SELECTED)) || (!sel && !(curbone->flag & BONE_SELECTED)) ) { EditBone *ebo; bPoseChannel *pchn; /* clear the bone->parent var of any bone that had this as its parent */ for (ebo = arm->edbo->first; ebo; ebo = ebo->next) { if (ebo->parent == curbone) { ebo->parent = NULL; ebo->temp = NULL; /* this is needed to prevent random crashes with in ED_armature_from_edit */ ebo->flag &= ~BONE_CONNECTED; } } /* clear the pchan->parent var of any pchan that had this as its parent */ for (pchn = ob->pose->chanbase.first; pchn; pchn = pchn->next) { if (pchn->parent == pchan) pchn->parent = NULL; } /* free any of the extra-data this pchan might have */ BKE_pose_channel_free(pchan); BKE_pose_channels_hash_free(ob->pose); /* get rid of unneeded bone */ bone_free(arm, curbone); BLI_freelinkN(&ob->pose->chanbase, pchan); } } /* exit editmode (recalculates pchans too) */ ED_armature_from_edit(ob); ED_armature_edit_free(ob); }
void ED_armature_transform_apply(Main *bmain, Object *ob, float mat[4][4], const bool do_props) { bArmature *arm = ob->data; /* Put the armature into editmode */ ED_armature_to_edit(arm); /* Transform the bones */ ED_armature_transform_bones(arm, mat, do_props); /* Turn the list into an armature */ ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); }
void ED_armature_transform(Main *bmain, bArmature *arm, float mat[4][4], const bool do_props) { if (arm->edbo) { ED_armature_transform_bones(arm, mat, do_props); } else { /* Put the armature into editmode */ ED_armature_to_edit(arm); /* Transform the bones */ ED_armature_transform_bones(arm, mat, do_props); /* Go back to object mode*/ ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); } }
void ED_armature_transform(struct bArmature *arm, float mat[4][4]) { if (arm->edbo) { ED_armature_transform_bones(arm, mat); } else { /* Put the armature into editmode */ ED_armature_to_edit(arm); /* Transform the bones */ ED_armature_transform_bones(arm, mat); /* Go back to object mode*/ ED_armature_from_edit(arm); ED_armature_edit_free(arm); } }
void ED_armature_apply_transform(Object *ob, float mat[4][4]) { EditBone *ebone; bArmature *arm = ob->data; float scale = mat4_to_scale(mat); /* store the scale of the matrix here to use on envelopes */ float mat3[3][3]; copy_m3_m4(mat3, mat); normalize_m3(mat3); /* Put the armature into editmode */ ED_armature_to_edit(ob); /* Do the rotations */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { float delta[3], tmat[3][3]; /* find the current bone's roll matrix */ sub_v3_v3v3(delta, ebone->tail, ebone->head); vec_roll_to_mat3(delta, ebone->roll, tmat); /* transform the roll matrix */ mul_m3_m3m3(tmat, mat3, tmat); /* transform the bone */ mul_m4_v3(mat, ebone->head); mul_m4_v3(mat, ebone->tail); /* apply the transfiormed roll back */ mat3_to_vec_roll(tmat, NULL, &ebone->roll); ebone->rad_head *= scale; ebone->rad_tail *= scale; ebone->dist *= scale; /* we could be smarter and scale by the matrix along the x & z axis */ ebone->xwidth *= scale; ebone->zwidth *= scale; } /* Turn the list into an armature */ ED_armature_from_edit(ob); ED_armature_edit_free(ob); }
// write bone nodes void ArmatureExporter::add_armature_bones(Object *ob_arm, ViewLayer *view_layer, SceneExporter *se, std::vector<Object *> &child_objects) { // write bone nodes bArmature *armature = (bArmature *)ob_arm->data; bool is_edited = armature->edbo != NULL; if (!is_edited) { ED_armature_to_edit(armature); } for (Bone *bone = (Bone *)armature->bonebase.first; bone; bone = bone->next) { add_bone_node(bone, ob_arm, se, child_objects); } if (!is_edited) { ED_armature_edit_free(armature); } }
/* 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; }
/* join armature exec is exported for use in object->join objects operator... */ int join_armature_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); bArmature *arm = (ob) ? ob->data : NULL; bPose *pose, *opose; bPoseChannel *pchan, *pchann; EditBone *curbone; float mat[4][4], oimat[4][4]; /* Ensure we're not in editmode and that the active object is an armature*/ if (!ob || ob->type != OB_ARMATURE) return OPERATOR_CANCELLED; if (!arm || arm->edbo) return OPERATOR_CANCELLED; /* Get editbones of active armature to add editbones to */ ED_armature_to_edit(ob); /* get pose of active object and move it out of posemode */ pose = ob->pose; ob->mode &= ~OB_MODE_POSE; CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases) { if ((base->object->type == OB_ARMATURE) && (base->object != ob)) { bArmature *curarm = base->object->data; /* Make a list of editbones in current armature */ ED_armature_to_edit(base->object); /* Get Pose of current armature */ opose = base->object->pose; base->object->mode &= ~OB_MODE_POSE; //BASACT->flag &= ~OB_MODE_POSE; /* Find the difference matrix */ invert_m4_m4(oimat, ob->obmat); mult_m4_m4m4(mat, oimat, base->object->obmat); /* Copy bones and posechannels from the object to the edit armature */ for (pchan = opose->chanbase.first; pchan; pchan = pchann) { pchann = pchan->next; curbone = editbone_name_exists(curarm->edbo, pchan->name); /* Get new name */ unique_editbone_name(arm->edbo, curbone->name, NULL); /* Transform the bone */ { float premat[4][4]; float postmat[4][4]; float difmat[4][4]; float imat[4][4]; float temp[3][3]; float delta[3]; /* Get the premat */ sub_v3_v3v3(delta, curbone->tail, curbone->head); vec_roll_to_mat3(delta, curbone->roll, temp); unit_m4(premat); /* Mat4MulMat34 only sets 3x3 part */ mul_m4_m3m4(premat, temp, mat); mul_m4_v3(mat, curbone->head); mul_m4_v3(mat, curbone->tail); /* Get the postmat */ sub_v3_v3v3(delta, curbone->tail, curbone->head); vec_roll_to_mat3(delta, curbone->roll, temp); copy_m4_m3(postmat, temp); /* Find the roll */ invert_m4_m4(imat, premat); mult_m4_m4m4(difmat, imat, postmat); curbone->roll -= (float)atan2(difmat[2][0], difmat[2][2]); } /* Fix Constraints and Other Links to this Bone and Armature */ joined_armature_fix_links(ob, base->object, pchan, curbone); /* Rename pchan */ BLI_strncpy(pchan->name, curbone->name, sizeof(pchan->name)); /* Jump Ship! */ BLI_remlink(curarm->edbo, curbone); BLI_addtail(arm->edbo, curbone); BLI_remlink(&opose->chanbase, pchan); BLI_addtail(&pose->chanbase, pchan); BKE_pose_channels_hash_free(opose); BKE_pose_channels_hash_free(pose); } ED_base_object_free_and_unlink(bmain, scene, base); } } CTX_DATA_END; DAG_relations_tag_update(bmain); /* because we removed object(s) */ ED_armature_from_edit(ob); ED_armature_edit_free(ob); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); return OPERATOR_FINISHED; }
/* 0 == do center, 1 == center new, 2 == center cursor */ void ED_armature_origin_set(Scene *scene, Object *ob, float cursor[3], int centermode, int around) { Object *obedit = scene->obedit; // XXX get from context EditBone *ebone; bArmature *arm = ob->data; float cent[3]; /* Put the armature into editmode */ if (ob != obedit) { ED_armature_to_edit(ob); obedit = NULL; /* we cant use this so behave as if there is no obedit */ } /* Find the centerpoint */ if (centermode == 2) { copy_v3_v3(cent, cursor); invert_m4_m4(ob->imat, ob->obmat); mul_m4_v3(ob->imat, cent); } else { if (around == V3D_CENTROID) { int total = 0; zero_v3(cent); for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { total += 2; add_v3_v3(cent, ebone->head); add_v3_v3(cent, ebone->tail); } if (total) { mul_v3_fl(cent, 1.0f / (float)total); } } else { float min[3], max[3]; INIT_MINMAX(min, max); for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { minmax_v3v3_v3(min, max, ebone->head); minmax_v3v3_v3(min, max, ebone->tail); } mid_v3_v3v3(cent, min, max); } } /* Do the adjustments */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { sub_v3_v3(ebone->head, cent); sub_v3_v3(ebone->tail, cent); } /* Turn the list into an armature */ if (obedit == NULL) { ED_armature_from_edit(ob); ED_armature_edit_free(ob); } /* Adjust object location for new centerpoint */ if (centermode && obedit == NULL) { mul_mat3_m4_v3(ob->obmat, cent); /* ommit translation part */ add_v3_v3(ob->loc, cent); } }
void ED_object_enter_editmode(bContext *C, int flag) { Scene *scene= CTX_data_scene(C); Base *base= NULL; Object *ob; ScrArea *sa= CTX_wm_area(C); View3D *v3d= NULL; int ok= 0; if (scene->id.lib) return; if (sa && sa->spacetype==SPACE_VIEW3D) v3d= sa->spacedata.first; if ((flag & EM_IGNORE_LAYER)==0) { base= CTX_data_active_base(C); /* active layer checked here for view3d */ if (base==NULL) return; else if (v3d && (base->lay & v3d->lay)==0) return; else if (!v3d && (base->lay & scene->lay)==0) return; } else { base= scene->basact; } if (ELEM3(NULL, base, base->object, base->object->data)) return; ob = base->object; if (object_data_is_libdata(ob)) { error_libdata(); return; } if (flag & EM_WAITCURSOR) waitcursor(1); ob->restore_mode = ob->mode; /* note, when switching scenes the object can have editmode data but * not be scene->obedit: bug 22954, this avoids calling self eternally */ if ((ob->restore_mode & OB_MODE_EDIT)==0) ED_object_toggle_modes(C, ob->mode); ob->mode= OB_MODE_EDIT; if (ob->type==OB_MESH) { BMEditMesh *em; ok= 1; scene->obedit = ob; /* context sees this */ EDBM_mesh_make(CTX_data_tool_settings(C), scene, ob); em = BMEdit_FromObject(ob); if (LIKELY(em)) { /* order doesn't matter */ EDBM_mesh_normals_update(em); BMEdit_RecalcTessellation(em); BM_mesh_select_mode_flush(em->bm); } WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_MESH, scene); } else if (ob->type==OB_ARMATURE) { bArmature *arm= base->object->data; if (!arm) return; /* * The function object_data_is_libdata make a problem here, the * check for ob->proxy return 0 and let blender enter to edit mode * this causes a crash when you try leave the edit mode. * The problem is that i can't remove the ob->proxy check from * object_data_is_libdata that prevent the bugfix #6614, so * i add this little hack here. */ if (arm->id.lib) { error_libdata(); return; } ok=1; scene->obedit= ob; ED_armature_to_edit(ob); /* to ensure all goes in restposition and without striding */ DAG_id_tag_update(&ob->id, OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME); // XXX: should this be OB_RECALC_DATA? WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_ARMATURE, scene); } else if (ob->type==OB_FONT) { scene->obedit= ob; // XXX for context ok= 1; make_editText(ob); WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_TEXT, scene); } else if (ob->type==OB_MBALL) { scene->obedit= ob; // XXX for context ok= 1; make_editMball(ob); WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_MBALL, scene); } else if (ob->type==OB_LATTICE) { scene->obedit= ob; // XXX for context ok= 1; make_editLatt(ob); WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_LATTICE, scene); } else if (ob->type==OB_SURF || ob->type==OB_CURVE) { ok= 1; scene->obedit= ob; // XXX for context make_editNurb(ob); WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_CURVE, scene); } if (ok) { DAG_id_tag_update(&ob->id, OB_RECALC_DATA); } else { scene->obedit= NULL; // XXX for context ob->mode &= ~OB_MODE_EDIT; WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, scene); } if (flag & EM_DO_UNDO) ED_undo_push(C, "Enter Editmode"); if (flag & EM_WAITCURSOR) waitcursor(0); }
/* set the current pose as the restpose */ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object bArmature *arm = BKE_armature_from_object(ob); bPose *pose; bPoseChannel *pchan; EditBone *curbone; /* don't check if editmode (should be done by caller) */ if (ob->type != OB_ARMATURE) return OPERATOR_CANCELLED; if (BKE_object_obdata_is_libdata(ob)) { BKE_report(op->reports, RPT_ERROR, "Cannot apply pose to lib-linked armature"); /* error_libdata(); */ return OPERATOR_CANCELLED; } /* helpful warnings... */ /* TODO: add warnings to be careful about actions, applying deforms first, etc. */ if (ob->adt && ob->adt->action) BKE_report(op->reports, RPT_WARNING, "Actions on this armature will be destroyed by this new rest pose as the " "transforms stored are relative to the old rest pose"); /* Get editbones of active armature to alter */ ED_armature_to_edit(arm); /* get pose of active object and move it out of posemode */ pose = ob->pose; for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { curbone = ED_armature_bone_find_name(arm->edbo, pchan->name); /* simply copy the head/tail values from pchan over to curbone */ copy_v3_v3(curbone->head, pchan->pose_head); copy_v3_v3(curbone->tail, pchan->pose_tail); /* fix roll: * 1. find auto-calculated roll value for this bone now * 2. remove this from the 'visual' y-rotation */ { float premat[3][3], imat[3][3], pmat[3][3], tmat[3][3]; float delta[3], eul[3]; /* obtain new auto y-rotation */ sub_v3_v3v3(delta, curbone->tail, curbone->head); vec_roll_to_mat3(delta, 0.0f, premat); invert_m3_m3(imat, premat); /* get pchan 'visual' matrix */ copy_m3_m4(pmat, pchan->pose_mat); /* remove auto from visual and get euler rotation */ mul_m3_m3m3(tmat, imat, pmat); mat3_to_eul(eul, tmat); /* just use this euler-y as new roll value */ curbone->roll = eul[1]; } /* clear transform values for pchan */ zero_v3(pchan->loc); zero_v3(pchan->eul); unit_qt(pchan->quat); unit_axis_angle(pchan->rotAxis, &pchan->rotAngle); pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f; /* set anim lock */ curbone->flag |= BONE_UNKEYED; } /* convert editbones back to bones, and then free the edit-data */ ED_armature_from_edit(arm); ED_armature_edit_free(arm); /* flush positions of posebones */ BKE_pose_where_is(scene, ob); /* fix parenting of objects which are bone-parented */ applyarmature_fix_boneparents(scene, ob); /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); return OPERATOR_FINISHED; }