Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/src/editarmature.c')
-rw-r--r--source/blender/src/editarmature.c5079
1 files changed, 0 insertions, 5079 deletions
diff --git a/source/blender/src/editarmature.c b/source/blender/src/editarmature.c
deleted file mode 100644
index 5ddf522e4a8..00000000000
--- a/source/blender/src/editarmature.c
+++ /dev/null
@@ -1,5079 +0,0 @@
-/**
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- * editarmature.c: Interface for creating and posing armature objects
- */
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "MEM_guardedalloc.h"
-
-#include "BMF_Api.h"
-
-#include "DNA_action_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_ID.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_nla_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_space_types.h"
-#include "DNA_userdef_types.h"
-#include "DNA_view3d_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_ipo_types.h"
-#include "DNA_curve_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_arithb.h"
-#include "BLI_editVert.h"
-#include "BLI_ghash.h"
-
-#include "BKE_action.h"
-#include "BKE_armature.h"
-#include "BKE_constraint.h"
-#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_global.h"
-#include "BKE_main.h"
-#include "BKE_object.h"
-#include "BKE_subsurf.h"
-#include "BKE_utildefines.h"
-#include "BKE_modifier.h"
-
-#include "BIF_editaction.h"
-#include "BIF_editmode_undo.h"
-#include "BIF_editdeform.h"
-#include "BIF_editarmature.h"
-#include "BIF_editconstraint.h"
-#include "BIF_gl.h"
-#include "BIF_graphics.h"
-#include "BIF_interface.h"
-#include "BIF_meshlaplacian.h"
-#include "BIF_meshtools.h"
-#include "BIF_poseobject.h"
-#include "BIF_mywindow.h"
-#include "BIF_resources.h"
-#include "BIF_screen.h"
-#include "BIF_space.h"
-#include "BIF_toolbox.h"
-#include "BIF_transform.h"
-
-#include "BDR_editobject.h"
-#include "BDR_drawobject.h"
-
-#include "BSE_edit.h"
-#include "BSE_view.h"
-#include "BSE_trans_types.h"
-
-#include "PIL_time.h"
-
-#include "reeb.h" // FIX ME
-
-#include "mydevice.h"
-#include "blendef.h"
-#include "nla.h"
-
-extern float center[3], centroid[3]; /* Originally defined in editobject.c */
-
-/* Macros */
-#define TEST_EDITARMATURE {if(G.obedit==0) return; if( (G.vd->lay & G.obedit->lay)==0 ) return;}
-
-/* prototypes for later */
-static EditBone *editbone_name_exists (ListBase *ebones, char *name); // proto for below
-
-/* **************** tools on Editmode Armature **************** */
-
-/* converts Bones to EditBone list, used for tools as well */
-void make_boneList(ListBase *list, ListBase *bones, EditBone *parent)
-{
- EditBone *eBone;
- Bone *curBone;
- float delta[3];
- float premat[3][3];
- float postmat[3][3];
- float imat[3][3];
- float difmat[3][3];
-
- for (curBone=bones->first; curBone; curBone=curBone->next) {
- eBone= MEM_callocN(sizeof(EditBone), "make_editbone");
-
- /* Copy relevant data from bone to eBone */
- eBone->parent= parent;
- BLI_strncpy(eBone->name, curBone->name, 32);
- eBone->flag = curBone->flag;
-
- /* fix selection flags */
- if (eBone->flag & BONE_SELECTED) {
- eBone->flag |= BONE_TIPSEL;
- if (eBone->parent && (eBone->flag & BONE_CONNECTED))
- eBone->parent->flag |= BONE_TIPSEL;
- else
- eBone->flag |= BONE_ROOTSEL;
- }
- else
- eBone->flag &= ~BONE_ROOTSEL;
-
- VECCOPY(eBone->head, curBone->arm_head);
- VECCOPY(eBone->tail, curBone->arm_tail);
-
- eBone->roll= 0.0;
-
- /* roll fixing */
- VecSubf(delta, eBone->tail, eBone->head);
- vec_roll_to_mat3(delta, 0.0, postmat);
-
- Mat3CpyMat4(premat, curBone->arm_mat);
-
- Mat3Inv(imat, postmat);
- Mat3MulMat3(difmat, imat, premat);
-
- eBone->roll = atan2(difmat[2][0], difmat[2][2]);
-
- /* rest of stuff copy */
- eBone->length= curBone->length;
- eBone->dist= curBone->dist;
- eBone->weight= curBone->weight;
- eBone->xwidth= curBone->xwidth;
- eBone->zwidth= curBone->zwidth;
- eBone->ease1= curBone->ease1;
- eBone->ease2= curBone->ease2;
- eBone->rad_head= curBone->rad_head;
- eBone->rad_tail= curBone->rad_tail;
- eBone->segments = curBone->segments;
- eBone->layer = curBone->layer;
-
- BLI_addtail(list, eBone);
-
- /* Add children if necessary */
- if (curBone->childbase.first)
- make_boneList(list, &curBone->childbase, eBone);
- }
-}
-
-/* nasty stuff for converting roll in editbones into bones */
-/* also sets restposition in armature (arm_mat) */
-static void fix_bonelist_roll (ListBase *bonelist, ListBase *editbonelist)
-{
- Bone *curBone;
- EditBone *ebone;
- float premat[3][3];
- float postmat[3][3];
- float difmat[3][3];
- float imat[3][3];
- float delta[3];
-
- for (curBone=bonelist->first; curBone; curBone=curBone->next) {
- /* sets local matrix and arm_mat (restpos) */
- where_is_armature_bone(curBone, curBone->parent);
-
- /* Find the associated editbone */
- for (ebone = editbonelist->first; ebone; ebone=ebone->next)
- if ((Bone*)ebone->temp == curBone)
- break;
-
- if (ebone) {
- /* Get the ebone premat */
- VecSubf(delta, ebone->tail, ebone->head);
- vec_roll_to_mat3(delta, ebone->roll, premat);
-
- /* Get the bone postmat */
- Mat3CpyMat4(postmat, curBone->arm_mat);
-
- Mat3Inv(imat, premat);
- Mat3MulMat3(difmat, imat, postmat);
-#if 0
- printf ("Bone %s\n", curBone->name);
- printmatrix4("premat", premat);
- printmatrix4("postmat", postmat);
- printmatrix4("difmat", difmat);
- printf ("Roll = %f\n", (-atan2(difmat[2][0], difmat[2][2]) * (180.0/M_PI)));
-#endif
- curBone->roll = -atan2(difmat[2][0], difmat[2][2]);
-
- /* and set restposition again */
- where_is_armature_bone(curBone, curBone->parent);
- }
- fix_bonelist_roll(&curBone->childbase, editbonelist);
- }
-}
-
-/* converts the editbones back to the armature */
-void editbones_to_armature (ListBase *list, Object *ob)
-{
- bArmature *arm;
- EditBone *eBone, *neBone;
- Bone *newBone;
- Object *obt;
-
- arm = get_armature(ob);
- if (!list) return;
- if (!arm) return;
-
- /* armature bones */
- free_bones(arm);
-
- /* remove zero sized bones, this gives instable restposes */
- for (eBone=list->first; eBone; eBone= neBone) {
- float len= VecLenf(eBone->head, eBone->tail);
- neBone= eBone->next;
- if (len <= FLT_EPSILON) {
- EditBone *fBone;
-
- /* Find any bones that refer to this bone */
- for (fBone=list->first; fBone; fBone= fBone->next) {
- if (fBone->parent==eBone)
- fBone->parent= eBone->parent;
- }
- printf("Warning: removed zero sized bone: %s\n", eBone->name);
- BLI_freelinkN(list, eBone);
- }
- }
-
- /* Copy the bones from the editData into the armature */
- for (eBone=list->first; eBone; eBone=eBone->next) {
- newBone= MEM_callocN(sizeof(Bone), "bone");
- eBone->temp= newBone; /* Associate the real Bones with the EditBones */
-
- BLI_strncpy(newBone->name, eBone->name, 32);
- memcpy(newBone->head, eBone->head, sizeof(float)*3);
- memcpy(newBone->tail, eBone->tail, sizeof(float)*3);
- newBone->flag= eBone->flag;
- if (eBone->flag & BONE_ACTIVE)
- newBone->flag |= BONE_SELECTED; /* important, editbones can be active with only 1 point selected */
- newBone->roll = 0.0f;
-
- newBone->weight = eBone->weight;
- newBone->dist = eBone->dist;
-
- newBone->xwidth = eBone->xwidth;
- newBone->zwidth = eBone->zwidth;
- newBone->ease1= eBone->ease1;
- newBone->ease2= eBone->ease2;
- newBone->rad_head= eBone->rad_head;
- newBone->rad_tail= eBone->rad_tail;
- newBone->segments= eBone->segments;
- newBone->layer = eBone->layer;
- }
-
- /* Fix parenting in a separate pass to ensure ebone->bone connections
- are valid at this point */
- for (eBone=list->first;eBone;eBone=eBone->next) {
- newBone= (Bone *)eBone->temp;
- if (eBone->parent) {
- newBone->parent= (Bone *)eBone->parent->temp;
- BLI_addtail(&newBone->parent->childbase, newBone);
-
- {
- float M_boneRest[3][3];
- float M_parentRest[3][3];
- float iM_parentRest[3][3];
- float delta[3];
-
- /* Get the parent's matrix (rotation only) */
- VecSubf(delta, eBone->parent->tail, eBone->parent->head);
- vec_roll_to_mat3(delta, eBone->parent->roll, M_parentRest);
-
- /* Get this bone's matrix (rotation only) */
- VecSubf(delta, eBone->tail, eBone->head);
- vec_roll_to_mat3(delta, eBone->roll, M_boneRest);
-
- /* Invert the parent matrix */
- Mat3Inv(iM_parentRest, M_parentRest);
-
- /* Get the new head and tail */
- VecSubf(newBone->head, eBone->head, eBone->parent->tail);
- VecSubf(newBone->tail, eBone->tail, eBone->parent->tail);
-
- Mat3MulVecfl(iM_parentRest, newBone->head);
- Mat3MulVecfl(iM_parentRest, newBone->tail);
- }
- }
- /* ...otherwise add this bone to the armature's bonebase */
- else
- BLI_addtail(&arm->bonebase, newBone);
- }
-
- /* Make a pass through the new armature to fix rolling */
- /* also builds restposition again (like where_is_armature) */
- fix_bonelist_roll(&arm->bonebase, list);
-
- /* so all users of this armature should get rebuilt */
- for (obt= G.main->object.first; obt; obt= obt->id.next) {
- if (obt->data==arm)
- armature_rebuild_pose(obt, arm);
- }
-
- DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
-}
-
-
-
-void apply_rot_armature (Object *ob, float mat[3][3])
-{
- ListBase list;
- EditBone *ebone;
- bArmature *arm;
- float scale = Mat3ToScalef(mat); /* store the scale of the matrix here to use on envelopes */
- arm = get_armature(ob);
-
- if (!arm)
- return;
-
- /* Put the armature into editmode */
- list.first= list.last = NULL;
- make_boneList(&list, &arm->bonebase, NULL);
-
- /* Do the rotations */
- for (ebone = list.first; ebone; ebone=ebone->next){
- Mat3MulVecfl(mat, ebone->head);
- Mat3MulVecfl(mat, ebone->tail);
-
- ebone->rad_head *= scale;
- ebone->rad_tail *= scale;
- ebone->dist *= scale;
- }
-
- /* Turn the list into an armature */
- editbones_to_armature(&list, ob);
-
- /* Free the editbones */
- if (list.first){
- BLI_freelistN (&list);
- }
-}
-
-/* 0 == do center, 1 == center new, 2 == center cursor */
-void docenter_armature (Object *ob, int centermode)
-{
- ListBase list;
- EditBone *ebone;
- bArmature *arm;
- float cent[3] = {0.0f, 0.0f, 0.0f};
- float min[3], max[3];
- float omat[3][3];
-
- arm = get_armature(ob);
- if (!arm) return;
-
- /* Put the armature into editmode */
- list.first= list.last = NULL;
- make_boneList(&list, &arm->bonebase, NULL);
-
- /* Find the centerpoint */
- if (centermode == 2) {
- VECCOPY(cent, give_cursor());
- Mat4Invert(ob->imat, ob->obmat);
- Mat4MulVecfl(ob->imat, cent);
- }
- else {
- INIT_MINMAX(min, max);
-
- for (ebone= list.first; ebone; ebone=ebone->next) {
- DO_MINMAX(ebone->head, min, max);
- DO_MINMAX(ebone->tail, min, max);
- }
-
- cent[0]= (min[0]+max[0])/2.0f;
- cent[1]= (min[1]+max[1])/2.0f;
- cent[2]= (min[2]+max[2])/2.0f;
- }
-
- /* Do the adjustments */
- for (ebone= list.first; ebone; ebone=ebone->next){
- VecSubf(ebone->head, ebone->head, cent);
- VecSubf(ebone->tail, ebone->tail, cent);
- }
-
- /* Turn the list into an armature */
- editbones_to_armature(&list, ob);
-
- /* Free the editbones */
- if (list.first){
- BLI_freelistN(&list);
- }
-
- /* Adjust object location for new centerpoint */
- if(centermode && G.obedit==0) {
- Mat3CpyMat4(omat, ob->obmat);
-
- Mat3MulVecfl(omat, cent);
- ob->loc[0]+= cent[0];
- ob->loc[1]+= cent[1];
- ob->loc[2]+= cent[2];
- }
-}
-
-/* helper for apply_armature_pose2bones - fixes parenting of objects that are bone-parented to armature */
-static void applyarmature_fix_boneparents (Object *armob)
-{
- Object *ob;
-
- /* go through all objects in database */
- for (ob= G.main->object.first; ob; ob= ob->id.next) {
- /* if parent is bone in this armature, apply corrections */
- if ((ob->parent == armob) && (ob->partype == PARBONE)) {
- /* apply current transform from parent (not yet destroyed),
- * then calculate new parent inverse matrix
- */
- apply_obmat(ob);
-
- what_does_parent(ob);
- Mat4Invert(ob->parentinv, workob.obmat);
- }
- }
-}
-
-/* set the current pose as the restpose */
-void apply_armature_pose2bones(void)
-{
- Object *ob;
- bArmature *arm;
- bPose *pose;
- bPoseChannel *pchan;
- EditBone *curbone;
-
- /* don't check if editmode (should be done by caller) */
- ob= OBACT;
- if (ob->type!=OB_ARMATURE) return;
- if (object_data_is_libdata(ob)) {
- error_libdata();
- return;
- }
- arm= get_armature(ob);
-
- /* helpful warnings... */
- // TODO: add warnings to be careful about actions, applying deforms first, etc.
-
- /* Get editbones of active armature to alter */
- if (G.edbo.first) BLI_freelistN(&G.edbo);
- make_boneList(&G.edbo, &arm->bonebase, NULL);
-
- /* get pose of active object and move it out of posemode */
- pose= ob->pose;
-
- for (pchan=pose->chanbase.first; pchan; pchan=pchan->next) {
- curbone= editbone_name_exists(&G.edbo, pchan->name);
-
- /* simply copy the head/tail values from pchan over to curbone */
- VECCOPY(curbone->head, pchan->pose_head);
- VECCOPY(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 */
- VecSubf(delta, curbone->tail, curbone->head);
- vec_roll_to_mat3(delta, 0.0, premat);
- Mat3Inv(imat, premat);
-
- /* get pchan 'visual' matrix */
- Mat3CpyMat4(pmat, pchan->pose_mat);
-
- /* remove auto from visual and get euler rotation */
- Mat3MulMat3(tmat, imat, pmat);
- Mat3ToEul(tmat, eul);
-
- /* just use this euler-y as new roll value */
- curbone->roll= eul[1];
- }
-
- /* clear transform values for pchan */
- pchan->loc[0]= pchan->loc[1]= pchan->loc[2]= 0;
- pchan->quat[1]= pchan->quat[2]= pchan->quat[3]= 0;
- pchan->quat[0]= pchan->size[0]= pchan->size[1]= pchan->size[2]= 1;
-
- /* set anim lock */
- curbone->flag |= BONE_UNKEYED;
- }
-
- /* convert editbones back to bones */
- editbones_to_armature(&G.edbo, ob);
- if (G.edbo.first) BLI_freelistN(&G.edbo);
-
- /* flush positions of posebones */
- where_is_pose(ob);
-
- /* fix parenting of objects which are bone-parented */
- applyarmature_fix_boneparents(ob);
-
- BIF_undo_push("Apply new restpose");
- allqueue(REDRAWVIEW3D, 0);
-}
-
-
-/* Helper function for armature joining - link fixing */
-static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone)
-{
- Object *ob;
- bPose *pose;
- bPoseChannel *pchant;
- bConstraint *con;
-
- /* let's go through all objects in database */
- for (ob= G.main->object.first; ob; ob= ob->id.next) {
- /* do some object-type specific things */
- if (ob->type == OB_ARMATURE) {
- pose= ob->pose;
- for (pchant= pose->chanbase.first; pchant; pchant= pchant->next) {
- for (con= pchant->constraints.first; con; con= con->next) {
- bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- /* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct= targets.first; ct; ct= ct->next) {
- if (ct->tar == srcArm) {
- if (strcmp(ct->subtarget, "")==0) {
- ct->tar = tarArm;
- }
- else if (strcmp(ct->subtarget, pchan->name)==0) {
- ct->tar = tarArm;
- strcpy(ct->subtarget, curbone->name);
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
-
- /* action constraint? */
- if (con->type == CONSTRAINT_TYPE_ACTION) {
- bActionConstraint *data= con->data;
- bAction *act;
- bActionChannel *achan;
-
- if (data->act) {
- act= data->act;
-
- for (achan= act->chanbase.first; achan; achan= achan->next) {
- if (strcmp(achan->name, pchan->name)==0)
- BLI_strncpy(achan->name, curbone->name, 32);
- }
- }
- }
-
- }
- }
- }
-
- /* fix object-level constraints */
- if (ob != srcArm) {
- for (con= ob->constraints.first; con; con= con->next) {
- bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- /* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct= targets.first; ct; ct= ct->next) {
- if (ct->tar == srcArm) {
- if (strcmp(ct->subtarget, "")==0) {
- ct->tar = tarArm;
- }
- else if (strcmp(ct->subtarget, pchan->name)==0) {
- ct->tar = tarArm;
- strcpy(ct->subtarget, curbone->name);
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
-
- /* See if an object is parented to this armature */
- if (ob->parent && (ob->parent == srcArm)) {
- /* Is object parented to a bone of this src armature? */
- if (ob->partype==PARBONE) {
- /* bone name in object */
- if (!strcmp(ob->parsubstr, pchan->name))
- BLI_strncpy(ob->parsubstr, curbone->name, 32);
- }
-
- /* make tar armature be new parent */
- ob->parent = tarArm;
- }
- }
-}
-
-int join_armature(void)
-{
- Object *ob;
- bArmature *arm;
- Base *base, *nextbase;
- bPose *pose, *opose;
- bPoseChannel *pchan, *pchann;
- ListBase ebbase, eblist;
- EditBone *curbone;
- float mat[4][4], oimat[4][4];
-
- /* Ensure we're not in editmode and that the active object is an armature*/
- /* if(G.obedit) return; */ /* Alredy checked in join_menu() */
-
- ob= OBACT;
- if (ob->type!=OB_ARMATURE) return 0;
- if (object_data_is_libdata(ob)) {
- error_libdata();
- return 0;
- }
- arm= get_armature(ob);
-
- /* Get editbones of active armature to add editbones to */
- ebbase.first=ebbase.last= NULL;
- make_boneList(&ebbase, &arm->bonebase, NULL);
-
- /* get pose of active object and move it out of posemode */
- pose= ob->pose;
- ob->flag &= ~OB_POSEMODE;
- BASACT->flag &= ~OB_POSEMODE;
-
- for (base=FIRSTBASE; base; base=nextbase) {
- nextbase = base->next;
- if (TESTBASE(base)){
- if ((base->object->type==OB_ARMATURE) && (base->object!=ob)) {
- /* Make a list of editbones in current armature */
- eblist.first=eblist.last= NULL;
- make_boneList(&eblist, &((bArmature *)base->object->data)->bonebase, NULL);
-
- /* Get Pose of current armature */
- opose= base->object->pose;
- base->object->flag &= ~OB_POSEMODE;
- BASACT->flag &= ~OB_POSEMODE;
-
- /* Find the difference matrix */
- Mat4Invert(oimat, ob->obmat);
- Mat4MulMat4(mat, base->object->obmat, oimat);
-
- /* 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(&eblist, pchan->name);
-
- /* Get new name */
- unique_editbone_name(&ebbase, curbone->name);
-
- /* 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 */
- VecSubf(delta, curbone->tail, curbone->head);
- vec_roll_to_mat3(delta, curbone->roll, temp);
-
- Mat4MulMat34(premat, temp, mat);
-
- Mat4MulVecfl(mat, curbone->head);
- Mat4MulVecfl(mat, curbone->tail);
-
- /* Get the postmat */
- VecSubf(delta, curbone->tail, curbone->head);
- vec_roll_to_mat3(delta, curbone->roll, temp);
- Mat4CpyMat3(postmat, temp);
-
- /* Find the roll */
- Mat4Invert(imat, premat);
- Mat4MulMat4(difmat, postmat, imat);
-
- curbone->roll -= 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 */
- sprintf(pchan->name, curbone->name);
-
- /* Jump Ship! */
- BLI_remlink(&eblist, curbone);
- BLI_addtail(&ebbase, curbone);
-
- BLI_remlink(&opose->chanbase, pchan);
- BLI_addtail(&pose->chanbase, pchan);
- }
-
- free_and_unlink_base(base);
- }
- }
- }
-
- DAG_scene_sort(G.scene); // because we removed object(s)
-
- editbones_to_armature(&ebbase, ob);
- if (ebbase.first) BLI_freelistN(&ebbase);
-
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWOOPS, 0);
- return 1;
-}
-
-/* Helper function for armature separating - link fixing */
-static void separated_armature_fix_links(Object *origArm, Object *newArm)
-{
- Object *ob;
- bPoseChannel *pchan, *pcha, *pchb;
- bConstraint *con;
- ListBase *opchans, *npchans;
-
- /* get reference to list of bones in original and new armatures */
- opchans= &origArm->pose->chanbase;
- npchans= &newArm->pose->chanbase;
-
- /* let's go through all objects in database */
- for (ob= G.main->object.first; ob; ob= ob->id.next) {
- /* do some object-type specific things */
- if (ob->type == OB_ARMATURE) {
- for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
- for (con= pchan->constraints.first; con; con= con->next) {
- bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- /* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct= targets.first; ct; ct= ct->next) {
- /* any targets which point to original armature are redirected to the new one only if:
- * - the target isn't origArm/newArm itself
- * - the target is one that can be found in newArm/origArm
- */
- if ((ct->tar == origArm) && (ct->subtarget[0] != 0)) {
- for (pcha=npchans->first, pchb=npchans->last; pcha && pchb; pcha=pcha->next, pchb=pchb->prev) {
- /* check if either one matches */
- if ( (strcmp(pcha->name, ct->subtarget)==0) ||
- (strcmp(pchb->name, ct->subtarget)==0) )
- {
- ct->tar= newArm;
- break;
- }
-
- /* check if both ends have met (to stop checking) */
- if (pcha == pchb) break;
- }
- }
- else if ((ct->tar == newArm) && (ct->subtarget[0] != 0)) {
- for (pcha=opchans->first, pchb=opchans->last; pcha && pchb; pcha=pcha->next, pchb=pchb->prev) {
- /* check if either one matches */
- if ( (strcmp(pcha->name, ct->subtarget)==0) ||
- (strcmp(pchb->name, ct->subtarget)==0) )
- {
- ct->tar= origArm;
- break;
- }
-
- /* check if both ends have met (to stop checking) */
- if (pcha == pchb) break;
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
- }
-
- /* fix object-level constraints */
- if (ob != origArm) {
- for (con= ob->constraints.first; con; con= con->next) {
- bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- /* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct= targets.first; ct; ct= ct->next) {
- /* any targets which point to original armature are redirected to the new one only if:
- * - the target isn't origArm/newArm itself
- * - the target is one that can be found in newArm/origArm
- */
- if ((ct->tar == origArm) && (ct->subtarget[0] != 0)) {
- for (pcha=npchans->first, pchb=npchans->last; pcha && pchb; pcha=pcha->next, pchb=pchb->prev) {
- /* check if either one matches */
- if ( (strcmp(pcha->name, ct->subtarget)==0) ||
- (strcmp(pchb->name, ct->subtarget)==0) )
- {
- ct->tar= newArm;
- break;
- }
-
- /* check if both ends have met (to stop checking) */
- if (pcha == pchb) break;
- }
- }
- else if ((ct->tar == newArm) && (ct->subtarget[0] != 0)) {
- for (pcha=opchans->first, pchb=opchans->last; pcha && pchb; pcha=pcha->next, pchb=pchb->prev) {
- /* check if either one matches */
- if ( (strcmp(pcha->name, ct->subtarget)==0) ||
- (strcmp(pchb->name, ct->subtarget)==0) )
- {
- ct->tar= origArm;
- break;
- }
-
- /* check if both ends have met (to stop checking) */
- if (pcha == pchb) break;
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
-
- /* See if an object is parented to this armature */
- if ((ob->parent) && (ob->parent == origArm)) {
- /* Is object parented to a bone of this src armature? */
- if (ob->partype==PARBONE) {
- /* bone name in object */
- for (pcha=npchans->first, pchb=npchans->last; pcha && pchb; pcha=pcha->next, pchb=pchb->prev) {
- /* check if either one matches */
- if ( (strcmp(pcha->name, ob->parsubstr)==0) ||
- (strcmp(pchb->name, ob->parsubstr)==0) )
- {
- ob->parent= newArm;
- break;
- }
-
- /* check if both ends have met (to stop checking) */
- if (pcha == pchb) break;
- }
- }
- }
- }
-}
-
-/* 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
- */
-static void separate_armature_bones (Object *ob, short sel)
-{
- ListBase edbo = {NULL, NULL};
- bArmature *arm= (bArmature *)ob->data;
- bPoseChannel *pchan, *pchann;
- EditBone *curbone;
-
- /* make local set of editbones to manipulate here */
- make_boneList(&edbo, &arm->bonebase, NULL);
-
- /* 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(&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= 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 editbones_to_armature */
- 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 */
- if (pchan->path) MEM_freeN(pchan->path);
- free_constraints(&pchan->constraints);
-
- /* get rid of unneeded bone */
- BLI_freelinkN(&edbo, curbone);
- BLI_freelinkN(&ob->pose->chanbase, pchan);
- }
- }
-
- /* exit editmode (recalculates pchans too) */
- editbones_to_armature(&edbo, ob);
- BLI_freelistN(&edbo);
-}
-
-/* separate selected bones into their armature */
-void separate_armature (void)
-{
- Object *oldob, *newob;
- Base *base, *oldbase, *newbase;
- bArmature *arm;
-
- if ( G.vd==0 || (G.vd->lay & G.obedit->lay)==0 ) return;
- if ( okee("Separate")==0 ) return;
-
- waitcursor(1);
-
- arm= G.obedit->data;
-
- /* 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 */
- base= FIRSTBASE;
- for (base= FIRSTBASE; base; base= base->next) {
- if (base->lay & G.vd->lay) {
- if (base->object==G.obedit) base->flag |= 1;
- else base->flag &= ~1;
- }
- }
-
- /* 1) store starting settings and exit editmode */
- oldob= G.obedit;
- oldbase= BASACT;
- oldob->flag &= ~OB_POSEMODE;
- oldbase->flag &= ~OB_POSEMODE;
-
- load_editArmature();
- free_editArmature();
-
- /* 2) duplicate base */
- adduplicate(1, USER_DUP_ARM); /* no transform and zero so do get a linked dupli */
-
- newbase= BASACT; /* basact is set in adduplicate() */
- 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_object_flush_update(G.scene, oldob, OB_RECALC_DATA); /* this is the original one */
- DAG_object_flush_update(G.scene, newob, OB_RECALC_DATA); /* this is the separated one */
-
-
- /* 5) restore original conditions */
- G.obedit= oldob;
- BASACT= oldbase;
- BASACT->flag |= SELECT;
-
- make_editArmature();
-
- /* recalc/redraw + cleanup */
- waitcursor(0);
-
- countall();
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- allqueue(REDRAWOOPS, 0);
-
- BIF_undo_push("Separate Armature");
-}
-
-/* **************** END tools on Editmode Armature **************** */
-/* **************** PoseMode & EditMode *************************** */
-
-/* only for opengl selection indices */
-Bone *get_indexed_bone (Object *ob, int index)
-{
- bPoseChannel *pchan;
- int a= 0;
-
- if(ob->pose==NULL) return NULL;
- index>>=16; // bone selection codes use left 2 bytes
-
- for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next, a++) {
- if(a==index) return pchan->bone;
- }
- return NULL;
-}
-
-/* See if there are any selected bones in this buffer */
-static void *get_bone_from_selectbuffer(Base *base, unsigned int *buffer, short hits, short findunsel)
-{
- Object *ob= base->object;
- Bone *bone;
- EditBone *ebone;
- void *firstunSel=NULL, *firstSel=NULL, *data;
- unsigned int hitresult;
- short i, takeNext=0, sel;
-
- for (i=0; i< hits; i++){
- hitresult = buffer[3+(i*4)];
-
- if (!(hitresult & BONESEL_NOSEL)) { // -1
- if(hitresult & BONESEL_ANY) { // to avoid including objects in selection
-
- hitresult &= ~(BONESEL_ANY);
- /* Determine what the current bone is */
- if (G.obedit==NULL || base->object!=G.obedit) {
- /* no singular posemode, so check for correct object */
- if(base->selcol == (hitresult & 0xFFFF)) {
- bone = get_indexed_bone(ob, hitresult);
-
- if (findunsel)
- sel = (bone->flag & BONE_SELECTED);
- else
- sel = !(bone->flag & BONE_SELECTED);
-
- data = bone;
- }
- else {
- data= NULL;
- sel= 0;
- }
- }
- else{
- ebone = BLI_findlink(&G.edbo, hitresult);
- if (findunsel)
- sel = (ebone->flag & BONE_SELECTED);
- else
- sel = !(ebone->flag & BONE_SELECTED);
-
- data = ebone;
- }
-
- if(data) {
- if (sel) {
- if(!firstSel) firstSel= data;
- takeNext=1;
- }
- else {
- if (!firstunSel)
- firstunSel=data;
- if (takeNext)
- return data;
- }
- }
- }
- }
- }
-
- if (firstunSel)
- return firstunSel;
- else
- return firstSel;
-}
-
-/* used by posemode as well editmode */
-static void *get_nearest_bone (short findunsel)
-{
- unsigned int buffer[MAXPICKBUF];
- short hits;
-
- persp(PERSP_VIEW);
-
- glInitNames();
- hits= view3d_opengl_select(buffer, MAXPICKBUF, 0, 0, 0, 0);
-
- if (hits>0)
- return get_bone_from_selectbuffer(BASACT, buffer, hits, findunsel);
-
- return NULL;
-}
-
-/* helper for setflag_sel_bone() */
-static void bone_setflag (int *bone, int flag, short mode)
-{
- if (bone && flag) {
- /* exception for inverse flags */
- if (flag == BONE_NO_DEFORM) {
- if (mode == 2)
- *bone |= flag;
- else if (mode == 1)
- *bone &= ~flag;
- else
- *bone ^= flag;
-
- }
- else {
- if (mode == 2)
- *bone &= ~flag;
- else if (mode == 1)
- *bone |= flag;
- else
- *bone ^= flag;
- }
- }
-}
-
-/* Get the first available child of an editbone */
-static EditBone *editbone_get_child(EditBone *pabone, short use_visibility)
-{
- Object *ob;
- bArmature *arm;
- EditBone *curbone, *chbone=NULL;
-
- if (!G.obedit) return NULL;
- else ob= G.obedit;
- arm= (bArmature *)ob->data;
-
- for (curbone= G.edbo.first; curbone; curbone= curbone->next) {
- if (curbone->parent == pabone) {
- if (use_visibility) {
- if ((arm->layer & curbone->layer) && !(pabone->flag & BONE_HIDDEN_A))
- chbone = curbone;
- }
- else
- chbone = curbone;
- }
- }
-
- return chbone;
-}
-
-void armature_select_hierarchy(short direction, short add_to_sel)
-{
- Object *ob;
- bArmature *arm;
- EditBone *curbone, *pabone, *chbone;
-
- if (!G.obedit) return;
- else ob= G.obedit;
- arm= (bArmature *)ob->data;
-
- for (curbone= G.edbo.first; curbone; curbone= curbone->next) {
- if (EBONE_VISIBLE(arm, curbone)) {
- if (curbone->flag & (BONE_ACTIVE)) {
- if (direction == BONE_SELECT_PARENT) {
- if (curbone->parent == NULL) continue;
- else pabone = curbone->parent;
-
- if (EBONE_VISIBLE(arm, pabone)) {
- pabone->flag |= (BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
- if (pabone->parent) pabone->parent->flag |= BONE_TIPSEL;
-
- if (!add_to_sel) curbone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
- curbone->flag &= ~BONE_ACTIVE;
- break;
- }
-
- }
- else { // BONE_SELECT_CHILD
- chbone = editbone_get_child(curbone, 1);
- if (chbone == NULL) continue;
-
- if (EBONE_VISIBLE(arm, chbone)) {
- chbone->flag |= (BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
-
- if (!add_to_sel) {
- curbone->flag &= ~(BONE_SELECTED|BONE_ROOTSEL);
- if (curbone->parent) curbone->parent->flag &= ~BONE_TIPSEL;
- }
- curbone->flag &= ~BONE_ACTIVE;
- break;
- }
- }
- }
- }
- }
-
- countall(); // flushes selection!
-
- allqueue (REDRAWVIEW3D, 0);
- allqueue (REDRAWBUTSEDIT, 0);
- allqueue (REDRAWBUTSOBJECT, 0);
- allqueue (REDRAWOOPS, 0);
-
- if (direction==BONE_SELECT_PARENT)
- BIF_undo_push("Select edit bone parent");
- if (direction==BONE_SELECT_CHILD)
- BIF_undo_push("Select edit bone child");
-}
-
-/* used by posemode and editmode */
-void setflag_armature (short mode)
-{
- Object *ob;
- bArmature *arm;
- int flag;
-
- /* get data */
- if (G.obedit)
- ob= G.obedit;
- else if (OBACT)
- ob= OBACT;
- else
- return;
- arm= (bArmature *)ob->data;
-
- /* get flag to set (sync these with the ones used in eBone_Flag */
- if (mode == 2)
- flag= pupmenu("Disable Setting%t|Draw Wire%x1|Deform%x2|Mult VG%x3|Hinge%x4|No Scale%x5|Locked%x6");
- else if (mode == 1)
- flag= pupmenu("Enable Setting%t|Draw Wire%x1|Deform%x2|Mult VG%x3|Hinge%x4|No Scale%x5|Locked%x6");
- else
- flag= pupmenu("Toggle Setting%t|Draw Wire%x1|Deform%x2|Mult VG%x3|Hinge%x4|No Scale%x5|Locked%x6");
- switch (flag) {
- case 1: flag = BONE_DRAWWIRE; break;
- case 2: flag = BONE_NO_DEFORM; break;
- case 3: flag = BONE_MULT_VG_ENV; break;
- case 4: flag = BONE_HINGE; break;
- case 5: flag = BONE_NO_SCALE; break;
- case 6: flag = BONE_EDITMODE_LOCKED; break;
- default: return;
- }
-
- /* determine which mode armature is in */
- if ((!G.obedit) && (ob->flag & OB_POSEMODE)) {
- /* deal with pose channels */
- bPoseChannel *pchan;
-
- /* set setting */
- for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
- if ((pchan->bone) && (arm->layer & pchan->bone->layer)) {
- if (pchan->bone->flag & BONE_SELECTED) {
- bone_setflag(&pchan->bone->flag, flag, mode);
- }
- }
- }
- }
- else if (G.obedit) {
- /* deal with editbones */
- EditBone *curbone;
-
- /* set setting */
- for (curbone= G.edbo.first; curbone; curbone= curbone->next) {
- if (arm->layer & curbone->layer) {
- if (curbone->flag & BONE_SELECTED) {
- bone_setflag(&curbone->flag, flag, mode);
- }
- }
- }
- }
-
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- allqueue(REDRAWBUTSOBJECT, 0);
- allqueue(REDRAWOOPS, 0);
-
- BIF_undo_push("Change Bone Setting");
-}
-
-/* **************** END PoseMode & EditMode *************************** */
-/* **************** Posemode stuff ********************** */
-
-
-static void selectconnected_posebonechildren (Object *ob, Bone *bone)
-{
- Bone *curBone;
-
- if (!(bone->flag & BONE_CONNECTED))
- return;
-
- select_actionchannel_by_name (ob->action, bone->name, !(G.qual & LR_SHIFTKEY));
-
- if (G.qual & LR_SHIFTKEY)
- bone->flag &= ~BONE_SELECTED;
- else
- bone->flag |= BONE_SELECTED;
-
- for (curBone=bone->childbase.first; curBone; curBone=curBone->next){
- selectconnected_posebonechildren (ob, curBone);
- }
-}
-
-/* within active object context */
-void selectconnected_posearmature(void)
-{
- Bone *bone, *curBone, *next;
- Object *ob= OBACT;
-
- if(!ob || !ob->pose) return;
-
- if (G.qual & LR_SHIFTKEY)
- bone= get_nearest_bone(0);
- else
- bone = get_nearest_bone(1);
-
- if (!bone)
- return;
-
- /* Select parents */
- for (curBone=bone; curBone; curBone=next){
- select_actionchannel_by_name (ob->action, curBone->name, !(G.qual & LR_SHIFTKEY));
- if (G.qual & LR_SHIFTKEY)
- curBone->flag &= ~BONE_SELECTED;
- else
- curBone->flag |= BONE_SELECTED;
-
- if (curBone->flag & BONE_CONNECTED)
- next=curBone->parent;
- else
- next=NULL;
- }
-
- /* Select children */
- for (curBone=bone->childbase.first; curBone; curBone=next){
- selectconnected_posebonechildren (ob, curBone);
- }
-
- countall(); // flushes selection!
-
- allqueue (REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- allqueue(REDRAWBUTSOBJECT, 0);
- allqueue (REDRAWACTION, 0);
- allqueue(REDRAWOOPS, 0);
- BIF_undo_push("Select connected");
-
-}
-
-/* **************** END Posemode stuff ********************** */
-/* **************** EditMode stuff ********************** */
-
-/* called in space.c */
-void selectconnected_armature(void)
-{
- EditBone *bone, *curBone, *next;
-
- if (G.qual & LR_SHIFTKEY)
- bone= get_nearest_bone(0);
- else
- bone= get_nearest_bone(1);
-
- if (!bone)
- return;
-
- /* Select parents */
- for (curBone=bone; curBone; curBone=next){
- if (G.qual & LR_SHIFTKEY){
- curBone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
- }
- else{
- curBone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
- }
-
- if (curBone->flag & BONE_CONNECTED)
- next=curBone->parent;
- else
- next=NULL;
- }
-
- /* Select children */
- while (bone){
- for (curBone=G.edbo.first; curBone; curBone=next){
- next = curBone->next;
- if (curBone->parent == bone){
- if (curBone->flag & BONE_CONNECTED){
- if (G.qual & LR_SHIFTKEY)
- curBone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
- else
- curBone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
- bone=curBone;
- break;
- }
- else{
- bone=NULL;
- break;
- }
- }
- }
- if (!curBone)
- bone=NULL;
-
- }
-
- countall(); // flushes selection!
-
- allqueue (REDRAWVIEW3D, 0);
- allqueue (REDRAWBUTSEDIT, 0);
- allqueue(REDRAWBUTSOBJECT, 0);
- allqueue(REDRAWOOPS, 0);
-
- BIF_undo_push("Select connected");
-
-}
-
-/* does bones and points */
-/* note that BONE ROOT only gets drawn for root bones (or without IK) */
-static EditBone * get_nearest_editbonepoint (int findunsel, int *selmask)
-{
- EditBone *ebone;
- unsigned int buffer[MAXPICKBUF];
- unsigned int hitresult, besthitresult=BONESEL_NOSEL;
- int i, mindep= 4;
- short hits, mval[2];
-
- persp(PERSP_VIEW);
-
- glInitNames();
-
- getmouseco_areawin(mval);
- hits= view3d_opengl_select(buffer, MAXPICKBUF, mval[0]-5, mval[1]-5, mval[0]+5, mval[1]+5);
- if(hits==0)
- hits= view3d_opengl_select(buffer, MAXPICKBUF, mval[0]-12, mval[1]-12, mval[0]+12, mval[1]+12);
-
- /* See if there are any selected bones in this group */
- if (hits>0) {
-
- if(hits==1) {
- if (!(buffer[3] & BONESEL_NOSEL))
- besthitresult= buffer[3];
- }
- else {
- for (i=0; i< hits; i++) {
- hitresult= buffer[3+(i*4)];
- if (!(hitresult & BONESEL_NOSEL)) {
- int dep;
-
- ebone = BLI_findlink(&G.edbo, hitresult & ~BONESEL_ANY);
-
- /* clicks on bone points get advantage */
- if( hitresult & (BONESEL_ROOT|BONESEL_TIP)) {
- /* but also the unselected one */
- if(findunsel) {
- if( (hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL)==0)
- dep= 1;
- else if( (hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL)==0)
- dep= 1;
- else
- dep= 2;
- }
- else dep= 2;
- }
- else {
- /* bone found */
- if(findunsel) {
- if((ebone->flag & BONE_SELECTED)==0)
- dep= 2;
- else
- dep= 3;
- }
- else dep= 3;
- }
- if(dep < mindep) {
- mindep= dep;
- besthitresult= hitresult;
- }
- }
- }
- }
-
- if (!(besthitresult & BONESEL_NOSEL)) {
-
- ebone= BLI_findlink(&G.edbo, besthitresult & ~BONESEL_ANY);
-
- *selmask = 0;
- if (besthitresult & BONESEL_ROOT)
- *selmask |= BONE_ROOTSEL;
- if (besthitresult & BONESEL_TIP)
- *selmask |= BONE_TIPSEL;
- if (besthitresult & BONESEL_BONE)
- *selmask |= BONE_SELECTED;
- return ebone;
- }
- }
- *selmask = 0;
- return NULL;
-}
-
-static void delete_bone(EditBone* exBone)
-{
- EditBone *curBone;
-
- /* Find any bones that refer to this bone */
- for (curBone=G.edbo.first;curBone;curBone=curBone->next) {
- if (curBone->parent==exBone) {
- curBone->parent=exBone->parent;
- curBone->flag &= ~BONE_CONNECTED;
- }
- }
-
- BLI_freelinkN(&G.edbo,exBone);
-}
-
-/* only editmode! */
-void delete_armature(void)
-{
- bArmature *arm= G.obedit->data;
- EditBone *curBone, *next;
- bConstraint *con;
-
- TEST_EDITARMATURE;
- if (okee("Erase selected bone(s)")==0) return;
-
- /* Select mirrored bones */
- if (arm->flag & ARM_MIRROR_EDIT) {
- for (curBone=G.edbo.first; curBone; curBone=curBone->next) {
- if (arm->layer & curBone->layer) {
- if (curBone->flag & BONE_SELECTED) {
- next = armature_bone_get_mirrored(curBone);
- if (next)
- next->flag |= BONE_SELECTED;
- }
- }
- }
- }
-
- /* First erase any associated pose channel */
- if (G.obedit->pose) {
- bPoseChannel *chan, *next;
- for (chan=G.obedit->pose->chanbase.first; chan; chan=next) {
- next= chan->next;
- curBone = editbone_name_exists(&G.edbo, chan->name);
-
- if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
- free_constraints(&chan->constraints);
- BLI_freelinkN (&G.obedit->pose->chanbase, chan);
- }
- else {
- for (con= chan->constraints.first; con; con= con->next) {
- bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct= targets.first; ct; ct= ct->next) {
- if (ct->tar == G.obedit) {
- if (ct->subtarget[0]) {
- curBone = editbone_name_exists(&G.edbo, ct->subtarget);
- if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
- con->flag |= CONSTRAINT_DISABLE;
- ct->subtarget[0]= 0;
- }
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
- }
- }
-
-
- for (curBone=G.edbo.first;curBone;curBone=next) {
- next=curBone->next;
- if (arm->layer & curBone->layer) {
- if (curBone->flag & BONE_SELECTED)
- delete_bone(curBone);
- }
- }
-
-
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- allqueue(REDRAWBUTSOBJECT, 0);
- allqueue(REDRAWOOPS, 0);
- countall(); // flushes selection!
-
- BIF_undo_push("Delete bone(s)");
-}
-
-/* context: editmode armature */
-void mouse_armature(void)
-{
- EditBone *nearBone = NULL, *ebone;
- int selmask;
-
- nearBone= get_nearest_editbonepoint(1, &selmask);
- if (nearBone) {
-
- if (!(G.qual & LR_SHIFTKEY)) {
- deselectall_armature(0, 0);
- }
-
- /* by definition the non-root connected bones have no root point drawn,
- so a root selection needs to be delivered to the parent tip,
- countall() (bad location) flushes these flags */
-
- if(selmask & BONE_SELECTED) {
- if(nearBone->parent && (nearBone->flag & BONE_CONNECTED)) {
- /* click in a chain */
- if(G.qual & LR_SHIFTKEY) {
- /* hold shift inverts this bone's selection */
- if(nearBone->flag & BONE_SELECTED) {
- /* deselect this bone */
- nearBone->flag &= ~(BONE_TIPSEL|BONE_SELECTED);
- /* only deselect parent tip if it is not selected */
- if(!(nearBone->parent->flag & BONE_SELECTED))
- nearBone->parent->flag &= ~BONE_TIPSEL;
- }
- else {
- /* select this bone */
- nearBone->flag |= BONE_TIPSEL;
- nearBone->parent->flag |= BONE_TIPSEL;
- }
- }
- else {
- /* select this bone */
- nearBone->flag |= BONE_TIPSEL;
- nearBone->parent->flag |= BONE_TIPSEL;
- }
- }
- else {
- if(G.qual & LR_SHIFTKEY) {
- /* hold shift inverts this bone's selection */
- if(nearBone->flag & BONE_SELECTED)
- nearBone->flag &= ~(BONE_TIPSEL|BONE_ROOTSEL);
- else
- nearBone->flag |= (BONE_TIPSEL|BONE_ROOTSEL);
- }
- else nearBone->flag |= (BONE_TIPSEL|BONE_ROOTSEL);
- }
- }
- else {
- if ((G.qual & LR_SHIFTKEY) && (nearBone->flag & selmask))
- nearBone->flag &= ~selmask;
- else
- nearBone->flag |= selmask;
- }
-
- countall(); // flushes selection!
-
- if(nearBone) {
- /* then now check for active status */
- for (ebone=G.edbo.first;ebone;ebone=ebone->next) ebone->flag &= ~BONE_ACTIVE;
- if(nearBone->flag & BONE_SELECTED) nearBone->flag |= BONE_ACTIVE;
- }
-
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- allqueue(REDRAWBUTSOBJECT, 0);
- allqueue(REDRAWOOPS, 0);
- }
-
- rightmouse_transform();
-}
-
-void free_editArmature(void)
-{
- /* Clear the editbones list */
- if (G.edbo.first)
- BLI_freelistN(&G.edbo);
-}
-
-void remake_editArmature(void)
-{
- if(okee("Reload original data")==0) return;
-
- make_editArmature();
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWOOPS, 0);
- allqueue(REDRAWBUTSHEAD, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- allqueue(REDRAWBUTSOBJECT, 0);
-
-// BIF_undo_push("Delete bone");
-}
-
-/* Put object in EditMode */
-void make_editArmature(void)
-{
- bArmature *arm;
-
- if (G.obedit==0) return;
-
- free_editArmature();
-
- arm= get_armature(G.obedit);
- if (!arm) return;
-
- make_boneList(&G.edbo, &arm->bonebase,NULL);
-}
-
-/* put EditMode back in Object */
-void load_editArmature(void)
-{
- bArmature *arm;
-
- arm= get_armature(G.obedit);
- if (!arm) return;
-
- editbones_to_armature(&G.edbo, G.obedit);
-}
-
-/* toggle==0: deselect
- toggle==1: swap (based on test)
- toggle==2: only active tag
- toggle==3: swap (no test)
-*/
-void deselectall_armature(int toggle, int doundo)
-{
- bArmature *arm= G.obedit->data;
- EditBone *eBone;
- int sel=1;
-
- if(toggle==1) {
- /* Determine if there are any selected bones
- And therefore whether we are selecting or deselecting */
- for (eBone=G.edbo.first;eBone;eBone=eBone->next){
-// if(arm->layer & eBone->layer) {
- if (eBone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)){
- sel=0;
- break;
- }
-// }
- }
- }
- else sel= toggle;
-
- /* Set the flags */
- for (eBone=G.edbo.first;eBone;eBone=eBone->next) {
- if (sel==3) {
- /* invert selection of bone */
- if ((arm->layer & eBone->layer) && (eBone->flag & BONE_HIDDEN_A)==0) {
- eBone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- eBone->flag &= ~BONE_ACTIVE;
- }
- }
- else if (sel==1) {
- /* select bone */
- if(arm->layer & eBone->layer && (eBone->flag & BONE_HIDDEN_A)==0) {
- eBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if(eBone->parent)
- eBone->parent->flag |= (BONE_TIPSEL);
- }
- }
- else if (sel==2) {
- /* clear active flag */
- eBone->flag &= ~(BONE_ACTIVE);
- }
- else {
- /* deselect bone */
- eBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL | BONE_ACTIVE);
- }
- }
-
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- allqueue(REDRAWBUTSOBJECT, 0);
- allqueue(REDRAWOOPS, 0);
-
- countall(); // flushes selection!
- if (doundo) {
- if (sel==1) BIF_undo_push("Select All");
- else BIF_undo_push("Deselect All");
- }
-}
-
-/* Sets the roll value of selected bones, depending on the mode
- * mode == 0: their z-axes point upwards
- * mode == 1: their z-axes point towards 3d-cursor
- */
-void auto_align_armature(short mode)
-{
- bArmature *arm= G.obedit->data;
- EditBone *ebone;
- EditBone *flipbone = NULL;
- float delta[3];
- float curmat[3][3];
- float *cursor= give_cursor();
-
- for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (arm->flag & ARM_MIRROR_EDIT)
- flipbone = armature_bone_get_mirrored(ebone);
-
- if ((ebone->flag & BONE_SELECTED) ||
- (flipbone && (flipbone->flag & BONE_SELECTED)))
- {
- /* specific method used to calculate roll depends on mode */
- if (mode == 1) {
- /* Z-Axis point towards cursor */
- float mat[4][4], tmat[4][4], imat[4][4];
- float rmat[4][4], rot[3];
- float vec[3];
-
- /* find the current bone matrix as a 4x4 matrix (in Armature Space) */
- VecSubf(delta, ebone->tail, ebone->head);
- vec_roll_to_mat3(delta, ebone->roll, curmat);
- Mat4CpyMat3(mat, curmat);
- VECCOPY(mat[3], ebone->head);
-
- /* multiply bone-matrix by object matrix (so that bone-matrix is in WorldSpace) */
- Mat4MulMat4(tmat, mat, G.obedit->obmat);
- Mat4Invert(imat, tmat);
-
- /* find position of cursor relative to bone */
- VecMat4MulVecfl(vec, imat, cursor);
-
- /* check that cursor is in usable position */
- if ((IS_EQ(vec[0], 0)==0) && (IS_EQ(vec[2], 0)==0)) {
- /* Compute a rotation matrix around y */
- rot[1] = atan2(vec[0], vec[2]);
- rot[0] = rot[2] = 0.0f;
- EulToMat4(rot, rmat);
-
- /* Multiply the bone matrix by rotation matrix. This should be new bone-matrix */
- Mat4MulMat4(tmat, rmat, mat);
- Mat3CpyMat4(curmat, tmat);
-
- /* Now convert from new bone-matrix, back to a roll value (in radians) */
- mat3_to_vec_roll(curmat, delta, &ebone->roll);
- }
- }
- else {
- /* Z-Axis Point Up */
- float xaxis[3]={1.0, 0.0, 0.0}, yaxis[3], zaxis[3]={0.0, 0.0, 1.0};
- float targetmat[3][3], imat[3][3], diffmat[3][3];
-
- /* Find the current bone matrix */
- VecSubf(delta, ebone->tail, ebone->head);
- vec_roll_to_mat3(delta, 0.0, curmat);
-
- /* Make new matrix based on y axis & z-up */
- VECCOPY (yaxis, curmat[1]);
-
- Mat3One(targetmat);
- VECCOPY (targetmat[0], xaxis);
- VECCOPY (targetmat[1], yaxis);
- VECCOPY (targetmat[2], zaxis);
- Mat3Ortho(targetmat);
-
- /* Find the difference between the two matrices */
- Mat3Inv(imat, targetmat);
- Mat3MulMat3(diffmat, imat, curmat);
-
- ebone->roll = atan2(diffmat[2][0], diffmat[2][2]);
- }
- }
- }
- }
-}
-
-/* **************** undo for armatures ************** */
-
-static void undoBones_to_editBones(void *lbv)
-{
- ListBase *lb= lbv;
- EditBone *ebo, *newebo;
-
- BLI_freelistN(&G.edbo);
-
- /* copy */
- for(ebo= lb->first; ebo; ebo= ebo->next) {
- newebo= MEM_dupallocN(ebo);
- ebo->temp= newebo;
- BLI_addtail(&G.edbo, newebo);
- }
-
- /* set pointers */
- for(newebo= G.edbo.first; newebo; newebo= newebo->next) {
- if(newebo->parent) newebo->parent= newebo->parent->temp;
- }
- /* be sure they dont hang ever */
- for(newebo= G.edbo.first; newebo; newebo= newebo->next) {
- newebo->temp= NULL;
- }
-}
-
-static void *editBones_to_undoBones(void)
-{
- ListBase *lb;
- EditBone *ebo, *newebo;
-
- lb= MEM_callocN(sizeof(ListBase), "listbase undo");
-
- /* copy */
- for(ebo= G.edbo.first; ebo; ebo= ebo->next) {
- newebo= MEM_dupallocN(ebo);
- ebo->temp= newebo;
- BLI_addtail(lb, newebo);
- }
-
- /* set pointers */
- for(newebo= lb->first; newebo; newebo= newebo->next) {
- if(newebo->parent) newebo->parent= newebo->parent->temp;
- }
-
- return lb;
-}
-
-static void free_undoBones(void *lbv)
-{
- ListBase *lb= lbv;
-
- BLI_freelistN(lb);
- MEM_freeN(lb);
-}
-
-/* and this is all the undo system needs to know */
-void undo_push_armature(char *name)
-{
- undo_editmode_push(name, free_undoBones, undoBones_to_editBones, editBones_to_undoBones, NULL);
-}
-
-
-
-/* **************** END EditMode stuff ********************** */
-/* *************** Adding stuff in editmode *************** */
-
-/* default bone add, returns it selected, but without tail set */
-static EditBone *add_editbone(char *name)
-{
- bArmature *arm= G.obedit->data;
-
- EditBone *bone= MEM_callocN(sizeof(EditBone), "eBone");
-
- BLI_strncpy(bone->name, name, 32);
- unique_editbone_name(&G.edbo, bone->name);
-
- BLI_addtail(&G.edbo, bone);
-
- bone->flag |= BONE_TIPSEL;
- bone->weight= 1.0F;
- bone->dist= 0.25F;
- bone->xwidth= 0.1;
- bone->zwidth= 0.1;
- bone->ease1= 1.0;
- bone->ease2= 1.0;
- bone->rad_head= 0.10;
- bone->rad_tail= 0.05;
- bone->segments= 1;
- bone->layer= arm->layer;
-
- return bone;
-}
-
-static void add_primitive_bone(Object *ob, short newob)
-{
- float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3];
- EditBone *bone;
-
- VECCOPY(curs, give_cursor());
-
- /* Get inverse point for head and orientation for tail */
- Mat4Invert(G.obedit->imat, G.obedit->obmat);
- Mat4MulVecfl(G.obedit->imat, curs);
-
- if ( !(newob) || (U.flag & USER_ADD_VIEWALIGNED) ) Mat3CpyMat4(obmat, G.vd->viewmat);
- else Mat3One(obmat);
-
- Mat3CpyMat4(viewmat, G.obedit->obmat);
- Mat3MulMat3(totmat, obmat, viewmat);
- Mat3Inv(imat, totmat);
-
- deselectall_armature(0, 0);
-
- /* Create a bone */
- bone= add_editbone("Bone");
-
- VECCOPY(bone->head, curs);
-
- if ( !(newob) || (U.flag & USER_ADD_VIEWALIGNED) )
- VecAddf(bone->tail, bone->head, imat[1]); // bone with unit length 1
- else
- VecAddf(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z
-
-}
-
-void add_primitiveArmature(int type)
-{
- short newob=0;
-
- if(G.scene->id.lib) return;
-
- /* this function also comes from an info window */
- if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return;
- if (G.vd==NULL) return;
-
- G.f &= ~(G_VERTEXPAINT+G_TEXTUREPAINT+G_WEIGHTPAINT+G_SCULPTMODE);
- setcursor_space(SPACE_VIEW3D, CURSOR_STD);
-
- check_editmode(OB_ARMATURE);
-
- /* If we're not the "obedit", make a new object and enter editmode */
- if (G.obedit==NULL) {
- add_object(OB_ARMATURE);
- base_init_from_view3d(BASACT, G.vd);
- G.obedit= BASACT->object;
-
- where_is_object(G.obedit);
-
- make_editArmature();
- setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
- newob=1;
- }
-
- /* no primitive support yet */
- add_primitive_bone(G.obedit, newob);
-
- countall(); // flushes selection!
-
- if ((newob) && !(U.flag & USER_ADD_EDITMODE)) {
- exit_editmode(2);
- }
-
- allqueue(REDRAWALL, 0);
- BIF_undo_push("Add primitive");
-}
-
-/* the ctrl-click method */
-void addvert_armature(void)
-{
- bArmature *arm= G.obedit->data;
- EditBone *ebone, *newbone, *flipbone;
- float *curs, mat[3][3],imat[3][3];
- int a, to_root= 0;
-
- TEST_EDITARMATURE;
-
- /* find the active or selected bone */
- for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & (BONE_ACTIVE|BONE_TIPSEL))
- break;
- }
- }
-
- if (ebone==NULL) {
- for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & (BONE_ACTIVE|BONE_ROOTSEL))
- break;
- }
- }
- if (ebone == NULL)
- return;
-
- to_root= 1;
- }
-
- deselectall_armature(0, 0);
-
- /* we re-use code for mirror editing... */
- flipbone= NULL;
- if (arm->flag & ARM_MIRROR_EDIT)
- flipbone= armature_bone_get_mirrored(ebone);
-
- for (a=0; a<2; a++) {
- if (a==1) {
- if (flipbone==NULL)
- break;
- else {
- SWAP(EditBone *, flipbone, ebone);
- }
- }
-
- newbone= add_editbone(ebone->name);
- newbone->flag |= BONE_ACTIVE;
-
- if (to_root) {
- VECCOPY(newbone->head, ebone->head);
- newbone->rad_head= ebone->rad_tail;
- newbone->parent= ebone->parent;
- }
- else {
- VECCOPY(newbone->head, ebone->tail);
- newbone->rad_head= ebone->rad_tail;
- newbone->parent= ebone;
- newbone->flag |= BONE_CONNECTED;
- }
-
- curs= give_cursor();
- VECCOPY(newbone->tail, curs);
- VecSubf(newbone->tail, newbone->tail, G.obedit->obmat[3]);
-
- if (a==1)
- newbone->tail[0]= -newbone->tail[0];
-
- Mat3CpyMat4(mat, G.obedit->obmat);
- Mat3Inv(imat, mat);
- Mat3MulVecfl(imat, newbone->tail);
-
- newbone->length= VecLenf(newbone->head, newbone->tail);
- newbone->rad_tail= newbone->length*0.05f;
- newbone->dist= newbone->length*0.25f;
-
- }
-
- countall();
-
- BIF_undo_push("Add Bone");
- allqueue(REDRAWVIEW3D, 0);
-}
-
-/* adds an EditBone between the nominated locations (should be in the right space) */
-static EditBone *add_points_bone (float head[], float tail[])
-{
- EditBone *ebo;
-
- ebo= add_editbone("Bone");
-
- VECCOPY(ebo->head, head);
- VECCOPY(ebo->tail, tail);
-
- return ebo;
-}
-
-
-static EditBone *get_named_editbone(char *name)
-{
- EditBone *eBone;
-
- if (name) {
- for (eBone=G.edbo.first; eBone; eBone=eBone->next) {
- if (!strcmp(name, eBone->name))
- return eBone;
- }
- }
-
- return NULL;
-}
-
-static void update_dup_subtarget(EditBone *dupBone)
-{
- /* If an edit bone has been duplicated, lets
- * update it's constraints if the subtarget
- * they point to has also been duplicated
- */
- EditBone *oldtarget, *newtarget;
- bPoseChannel *chan;
- bConstraint *curcon;
- ListBase *conlist;
-
- if ( (chan = verify_pose_channel(OBACT->pose, dupBone->name)) ) {
- if ( (conlist = &chan->constraints) ) {
- for (curcon = conlist->first; curcon; curcon=curcon->next) {
- /* does this constraint have a subtarget in
- * this armature?
- */
- bConstraintTypeInfo *cti= constraint_get_typeinfo(curcon);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(curcon, &targets);
-
- for (ct= targets.first; ct; ct= ct->next) {
- if ((ct->tar == G.obedit) && (ct->subtarget[0])) {
- oldtarget = get_named_editbone(ct->subtarget);
- if (oldtarget) {
- /* was the subtarget bone duplicated too? If
- * so, update the constraint to point at the
- * duplicate of the old subtarget.
- */
- if (oldtarget->flag & BONE_SELECTED){
- newtarget = (EditBone *) oldtarget->temp;
- strcpy(ct->subtarget, newtarget->name);
- }
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(curcon, &targets, 0);
- }
- }
- }
- }
-}
-
-
-void adduplicate_armature(void)
-{
- bArmature *arm= G.obedit->data;
- EditBone *eBone = NULL;
- EditBone *curBone;
- EditBone *firstDup=NULL; /* The beginning of the duplicated bones in the edbo list */
-
- countall(); // flushes selection!
-
- /* Select mirrored bones */
- if (arm->flag & ARM_MIRROR_EDIT) {
- for (curBone=G.edbo.first; curBone; curBone=curBone->next) {
- if (EBONE_VISIBLE(arm, curBone)) {
- if (curBone->flag & BONE_SELECTED) {
- eBone = armature_bone_get_mirrored(curBone);
- if (eBone)
- eBone->flag |= BONE_SELECTED;
- }
- }
- }
- }
-
- /* Find the selected bones and duplicate them as needed */
- for (curBone=G.edbo.first; curBone && curBone!=firstDup; curBone=curBone->next) {
- if (EBONE_VISIBLE(arm, curBone)) {
- if (curBone->flag & BONE_SELECTED) {
- eBone=MEM_callocN(sizeof(EditBone), "addup_editbone");
- eBone->flag |= BONE_SELECTED;
-
- /* Copy data from old bone to new bone */
- memcpy(eBone, curBone, sizeof(EditBone));
-
- curBone->temp = eBone;
- eBone->temp = curBone;
-
- unique_editbone_name(&G.edbo, eBone->name);
- BLI_addtail(&G.edbo, eBone);
- if (!firstDup)
- firstDup=eBone;
-
- /* Lets duplicate the list of constraints that the
- * current bone has.
- */
- if (OBACT->pose) {
- bPoseChannel *chanold, *channew;
- ListBase *listold, *listnew;
-
- chanold = verify_pose_channel(OBACT->pose, curBone->name);
- if (chanold) {
- listold = &chanold->constraints;
- if (listold) {
- /* WARNING: this creates a new posechannel, but there will not be an attached bone
- * yet as the new bones created here are still 'EditBones' not 'Bones'.
- */
- channew =
- verify_pose_channel(OBACT->pose, eBone->name);
- if (channew) {
- /* copy transform locks */
- channew->protectflag = chanold->protectflag;
-
- /* copy bone group */
- channew->agrp_index= chanold->agrp_index;
-
- /* ik (dof) settings */
- channew->ikflag = chanold->ikflag;
- VECCOPY(channew->limitmin, chanold->limitmin);
- VECCOPY(channew->limitmax, chanold->limitmax);
- VECCOPY(channew->stiffness, chanold->stiffness);
- channew->ikstretch= chanold->ikstretch;
-
- /* constraints */
- listnew = &channew->constraints;
- copy_constraints(listnew, listold);
-
- /* custom shape */
- channew->custom= chanold->custom;
- }
- }
- }
- }
- }
- }
- }
-
- /* Run though the list and fix the pointers */
- for (curBone=G.edbo.first; curBone && curBone!=firstDup; curBone=curBone->next) {
- if (EBONE_VISIBLE(arm, curBone)) {
- if (curBone->flag & BONE_SELECTED) {
- eBone=(EditBone*) curBone->temp;
-
- /* If this bone has no parent,
- Set the duplicate->parent to NULL
- */
- if (!curBone->parent)
- eBone->parent = NULL;
- /* If this bone has a parent that IS selected,
- Set the duplicate->parent to the curBone->parent->duplicate
- */
- else if (curBone->parent->flag & BONE_SELECTED)
- eBone->parent= (EditBone *)curBone->parent->temp;
- /* If this bone has a parent that IS not selected,
- Set the duplicate->parent to the curBone->parent
- */
- else {
- eBone->parent=(EditBone*) curBone->parent;
- eBone->flag &= ~BONE_CONNECTED;
- }
-
- /* Lets try to fix any constraint subtargets that might
- have been duplicated */
- update_dup_subtarget(eBone);
- }
- }
- }
-
- /* Deselect the old bones and select the new ones */
-
- for (curBone=G.edbo.first; curBone && curBone!=firstDup; curBone=curBone->next) {
- if (EBONE_VISIBLE(arm, curBone))
- curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL | BONE_ACTIVE);
- }
-
- BIF_TransformSetUndo("Add Duplicate");
- initTransform(TFM_TRANSLATION, CTX_NO_PET);
- Transform();
-
- allqueue(REDRAWBUTSEDIT, 0);
- allqueue(REDRAWBUTSOBJECT, 0);
- allqueue(REDRAWOOPS, 0);
-}
-
-
-
-/* *************** END Adding stuff in editmode *************** */
-/* ************** Add/Remove stuff in editmode **************** */
-
-/* temporary data-structure for merge/fill bones */
-typedef struct EditBonePoint {
- struct EditBonePoint *next, *prev;
-
- EditBone *head_owner; /* EditBone which uses this point as a 'head' point */
- EditBone *tail_owner; /* EditBone which uses this point as a 'tail' point */
-
- float vec[3]; /* the actual location of the point in local/EditMode space */
-} EditBonePoint;
-
-/* find chain-tips (i.e. bones without children) */
-static void chains_find_tips (ListBase *list)
-{
- EditBone *curBone, *ebo;
- LinkData *ld;
-
- /* note: this is potentially very slow ... there's got to be a better way */
- for (curBone= G.edbo.first; curBone; curBone= curBone->next) {
- short stop= 0;
-
- /* is this bone contained within any existing chain? (skip if so) */
- for (ld= list->first; ld; ld= ld->next) {
- for (ebo= ld->data; ebo; ebo= ebo->parent) {
- if (ebo == curBone) {
- stop= 1;
- break;
- }
- }
-
- if (stop) break;
- }
- /* skip current bone if it is part of an existing chain */
- if (stop) continue;
-
- /* is any existing chain part of the chain formed by this bone? */
- stop= 0;
- for (ebo= curBone->parent; ebo; ebo= ebo->parent) {
- for (ld= list->first; ld; ld= ld->next) {
- if (ld->data == ebo) {
- ld->data= curBone;
- stop= 1;
- break;
- }
- }
-
- if (stop) break;
- }
- /* current bone has already been added to a chain? */
- if (stop) continue;
-
- /* add current bone to a new chain */
- ld= MEM_callocN(sizeof(LinkData), "BoneChain");
- ld->data= curBone;
- BLI_addtail(list, ld);
- }
-}
-
-
-static void fill_add_joint (EditBone *ebo, short eb_tail, ListBase *points)
-{
- EditBonePoint *ebp;
- float vec[3];
- short found= 0;
-
- if (eb_tail) {
- VECCOPY(vec, ebo->tail);
- }
- else {
- VECCOPY(vec, ebo->head);
- }
-
- for (ebp= points->first; ebp; ebp= ebp->next) {
- if (VecEqual(ebp->vec, vec)) {
- if (eb_tail) {
- if ((ebp->head_owner) && (ebp->head_owner->parent == ebo)) {
- /* so this bone's tail owner is this bone */
- ebp->tail_owner= ebo;
- found= 1;
- break;
- }
- }
- else {
- if ((ebp->tail_owner) && (ebo->parent == ebp->tail_owner)) {
- /* so this bone's head owner is this bone */
- ebp->head_owner= ebo;
- found = 1;
- break;
- }
- }
- }
- }
-
- /* allocate a new point if no existing point was related */
- if (found == 0) {
- ebp= MEM_callocN(sizeof(EditBonePoint), "EditBonePoint");
-
- if (eb_tail) {
- VECCOPY(ebp->vec, ebo->tail);
- ebp->tail_owner= ebo;
- }
- else {
- VECCOPY(ebp->vec, ebo->head);
- ebp->head_owner= ebo;
- }
-
- BLI_addtail(points, ebp);
- }
-}
-
-/* bone adding between selected joints */
-void fill_bones_armature(void)
-{
- bArmature *arm= G.obedit->data;
- EditBone *ebo, *newbone=NULL;
- ListBase points = {NULL, NULL};
- int count;
-
- /* loop over all bones, and only consider if visible */
- for (ebo= G.edbo.first; ebo; ebo= ebo->next) {
- if (EBONE_VISIBLE(arm, ebo)) {
- if (!(ebo->flag & BONE_CONNECTED) && (ebo->flag & BONE_ROOTSEL))
- fill_add_joint(ebo, 0, &points);
- if (ebo->flag & BONE_TIPSEL)
- fill_add_joint(ebo, 1, &points);
- }
- }
-
- /* the number of joints determines how we fill:
- * 1) between joint and cursor (joint=head, cursor=tail)
- * 2) between the two joints (order is dependent on active-bone/hierachy)
- * 3+) error (a smarter method involving finding chains needs to be worked out
- */
- count= BLI_countlist(&points);
-
- if (count == 0) {
- error("No joints selected");
- return;
- }
- else if (count == 1) {
- EditBonePoint *ebp;
- float curs[3];
-
- /* Get Points - selected joint */
- ebp= (EditBonePoint *)points.first;
-
- /* Get points - cursor (tail) */
- VECCOPY (curs, give_cursor());
-
- Mat4Invert(G.obedit->imat, G.obedit->obmat);
- Mat4MulVecfl(G.obedit->imat, curs);
-
- /* Create a bone */
- newbone= add_points_bone(ebp->vec, curs);
- }
- else if (count == 2) {
- EditBonePoint *ebp, *ebp2;
- float head[3], tail[3];
- short headtail = 0;
-
- /* check that the points don't belong to the same bone */
- ebp= (EditBonePoint *)points.first;
- ebp2= ebp->next;
-
- if ((ebp->head_owner==ebp2->tail_owner) && (ebp->head_owner!=NULL)) {
- error("Same bone selected...");
- BLI_freelistN(&points);
- return;
- }
- if ((ebp->tail_owner==ebp2->head_owner) && (ebp->tail_owner!=NULL)) {
- error("Same bone selected...");
- BLI_freelistN(&points);
- return;
- }
-
- /* find which one should be the 'head' */
- if ((ebp->head_owner && ebp2->head_owner) || (ebp->tail_owner && ebp2->tail_owner)) {
- /* rule: whichever one is closer to 3d-cursor */
- float curs[3];
- float vecA[3], vecB[3];
- float distA, distB;
-
- /* get cursor location */
- VECCOPY(curs, give_cursor());
-
- Mat4Invert(G.obedit->imat, G.obedit->obmat);
- Mat4MulVecfl(G.obedit->imat, curs);
-
- /* get distances */
- VecSubf(vecA, ebp->vec, curs);
- VecSubf(vecB, ebp2->vec, curs);
- distA= VecLength(vecA);
- distB= VecLength(vecB);
-
- /* compare distances - closer one therefore acts as direction for bone to go */
- headtail= (distA < distB) ? 2 : 1;
- }
- else if (ebp->head_owner) {
- headtail = 1;
- }
- else if (ebp2->head_owner) {
- headtail = 2;
- }
-
- /* assign head/tail combinations */
- if (headtail == 2) {
- VECCOPY(head, ebp->vec);
- VECCOPY(tail, ebp2->vec);
- }
- else if (headtail == 1) {
- VECCOPY(head, ebp2->vec);
- VECCOPY(tail, ebp->vec);
- }
-
- /* add new bone and parent it to the appropriate end */
- if (headtail) {
- newbone= add_points_bone(head, tail);
-
- /* do parenting (will need to set connected flag too) */
- if (headtail == 2) {
- /* ebp tail or head - tail gets priority */
- if (ebp->tail_owner)
- newbone->parent= ebp->tail_owner;
- else
- newbone->parent= ebp->head_owner;
- }
- else {
- /* ebp2 tail or head - tail gets priority */
- if (ebp2->tail_owner)
- newbone->parent= ebp2->tail_owner;
- else
- newbone->parent= ebp2->head_owner;
- }
-
- newbone->flag |= BONE_CONNECTED;
- }
- }
- else {
- // FIXME.. figure out a method for multiple bones
- error("Too many points selected");
- printf("Points selected: %d \n", count);
- BLI_freelistN(&points);
- return;
- }
-
- /* free points */
- BLI_freelistN(&points);
-
- /* undo + updates */
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- BIF_undo_push("Fill Bones");
-}
-
-/* this function merges between two bones, removes them and those in-between,
- * and adjusts the parent relationships for those in-between
- */
-static void bones_merge(EditBone *start, EditBone *end, EditBone *endchild, ListBase *chains)
-{
- EditBone *ebo, *ebone, *newbone;
- LinkData *chain;
- float head[3], tail[3];
-
- /* check if same bone */
- if (start == end) {
- printf("Error: same bone! \n");
- printf("\tstart = %s, end = %s \n", start->name, end->name);
- }
-
- /* step 1: add a new bone
- * - head = head/tail of start (default head)
- * - tail = head/tail of end (default tail)
- * - parent = parent of start
- */
- if ((start->flag & BONE_TIPSEL) && !(start->flag & (BONE_SELECTED|BONE_ACTIVE))) {
- VECCOPY(head, start->tail);
- }
- else {
- VECCOPY(head, start->head);
- }
- if ((end->flag & BONE_ROOTSEL) && !(end->flag & (BONE_SELECTED|BONE_ACTIVE))) {
- VECCOPY(tail, end->head);
- }
- else {
- VECCOPY(tail, end->tail);
- }
- newbone= add_points_bone(head, tail);
- newbone->parent = start->parent;
-
- /* step 2a: parent children of in-between bones to newbone */
- for (chain= chains->first; chain; chain= chain->next) {
- /* ick: we need to check if parent of each bone in chain is one of the bones in the */
- for (ebo= chain->data; ebo; ebo= ebo->parent) {
- short found= 0;
-
- /* try to find which bone from the list to be removed, is the parent */
- for (ebone= end; ebone; ebone= ebone->parent) {
- if (ebo->parent == ebone) {
- found= 1;
- break;
- }
- }
-
- /* adjust this bone's parent to newbone then */
- if (found) {
- ebo->parent= newbone;
- break;
- }
- }
- }
-
- /* step 2b: parent child of end to newbone (child from this chain) */
- if (endchild)
- endchild->parent= newbone;
-
- /* step 3: delete all bones between and including start and end */
- for (ebo= end; ebo; ebo= ebone) {
- ebone= (ebo == start) ? (NULL) : (ebo->parent);
- BLI_freelinkN(&G.edbo, ebo);
- }
-}
-
-/* bone merging - has a menu! */
-void merge_armature(void)
-{
- bArmature *arm= G.obedit->data;
- short val= 0;
-
- /* process a menu to determine how to merge */
- // TODO: there's room for more modes of merging stuff...
- val= pupmenu("Merge Selected Bones%t|Within Chains%x1");
- if (val <= 0) return;
-
- if (val == 1) {
- /* go down chains, merging bones */
- ListBase chains = {NULL, NULL};
- LinkData *chain, *nchain;
- EditBone *ebo;
-
- /* get chains (ends on chains) */
- chains_find_tips(&chains);
- if (chains.first == NULL) return;
-
- /* each 'chain' is the last bone in the chain (with no children) */
- for (chain= chains.first; chain; chain= nchain) {
- EditBone *bstart= NULL, *bend= NULL;
- EditBone *bchild= NULL, *child=NULL;
-
- /* temporarily remove chain from list of chains */
- nchain= chain->next;
- BLI_remlink(&chains, chain);
-
- /* only consider bones that are visible and selected */
- for (ebo=chain->data; ebo; child=ebo, ebo=ebo->parent) {
- /* check if visible + selected */
- if ( EBONE_VISIBLE(arm, ebo) &&
- ((ebo->flag & BONE_CONNECTED) || (ebo->parent==NULL)) &&
- (ebo->flag & (BONE_SELECTED|BONE_ACTIVE)) )
- {
- /* set either end or start (end gets priority, unless it is already set) */
- if (bend == NULL) {
- bend= ebo;
- bchild= child;
- }
- else
- bstart= ebo;
- }
- else {
- /* chain is broken... merge any continous segments then clear */
- if (bstart && bend)
- bones_merge(bstart, bend, bchild, &chains);
-
- bstart = NULL;
- bend = NULL;
- bchild = NULL;
- }
- }
-
- /* merge from bstart to bend if something not merged */
- if (bstart && bend)
- bones_merge(bstart, bend, bchild, &chains);
-
- /* put back link */
- BLI_insertlinkbefore(&chains, nchain, chain);
- }
-
- BLI_freelistN(&chains);
- }
-
- /* undo + updates */
- countall();
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- BIF_undo_push("Merge Bones");
-}
-
-/* ************** END Add/Remove stuff in editmode ************ */
-/* *************** Tools in editmode *********** */
-
-
-void hide_selected_armature_bones(void)
-{
- bArmature *arm= G.obedit->data;
- EditBone *ebone;
-
- for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & (BONE_SELECTED)) {
- ebone->flag &= ~(BONE_TIPSEL|BONE_SELECTED|BONE_ROOTSEL|BONE_ACTIVE);
- ebone->flag |= BONE_HIDDEN_A;
- }
- }
- }
- countall();
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- BIF_undo_push("Hide Bones");
-}
-
-void hide_unselected_armature_bones(void)
-{
- EditBone *ebone;
-
- for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
- bArmature *arm= G.obedit->data;
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & (BONE_TIPSEL|BONE_SELECTED|BONE_ROOTSEL));
- else {
- ebone->flag &= ~BONE_ACTIVE;
- ebone->flag |= BONE_HIDDEN_A;
- }
- }
- }
- countall();
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- BIF_undo_push("Hide Unselected Bones");
-}
-
-void show_all_armature_bones(void)
-{
- EditBone *ebone;
-
- for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
- bArmature *arm= G.obedit->data;
- if(arm->layer & ebone->layer) {
- if (ebone->flag & BONE_HIDDEN_A) {
- ebone->flag |= (BONE_TIPSEL|BONE_SELECTED|BONE_ROOTSEL);
- ebone->flag &= ~BONE_HIDDEN_A;
- }
- }
- }
- countall();
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- BIF_undo_push("Reveal Bones");
-}
-
-/* check for null, before calling! */
-static void bone_connect_to_existing_parent(EditBone *bone)
-{
- bone->flag |= BONE_CONNECTED;
- VECCOPY(bone->head, bone->parent->tail);
- bone->rad_head = bone->parent->rad_tail;
-}
-
-static void bone_connect_to_new_parent(EditBone *selbone, EditBone *actbone, short mode)
-{
- EditBone *ebone;
- float offset[3];
-
- if ((selbone->parent) && (selbone->flag & BONE_CONNECTED))
- selbone->parent->flag &= ~(BONE_TIPSEL);
-
- /* make actbone the parent of selbone */
- selbone->parent= actbone;
-
- /* in actbone tree we cannot have a loop */
- for (ebone= actbone->parent; ebone; ebone= ebone->parent) {
- if (ebone->parent==selbone) {
- ebone->parent= NULL;
- ebone->flag &= ~BONE_CONNECTED;
- }
- }
-
- if (mode == 1) {
- /* Connected: Child bones will be moved to the parent tip */
- selbone->flag |= BONE_CONNECTED;
- VecSubf(offset, actbone->tail, selbone->head);
-
- VECCOPY(selbone->head, actbone->tail);
- selbone->rad_head= actbone->rad_tail;
-
- VecAddf(selbone->tail, selbone->tail, offset);
-
- /* offset for all its children */
- for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
- EditBone *par;
-
- for (par= ebone->parent; par; par= par->parent) {
- if (par==selbone) {
- VecAddf(ebone->head, ebone->head, offset);
- VecAddf(ebone->tail, ebone->tail, offset);
- break;
- }
- }
- }
- }
- else {
- /* Offset: Child bones will retain their distance from the parent tip */
- selbone->flag &= ~BONE_CONNECTED;
- }
-}
-
-void make_bone_parent(void)
-{
- bArmature *arm= G.obedit->data;
- EditBone *actbone, *ebone, *selbone;
- EditBone *flipbone, *flippar;
- short allchildbones= 0, foundselbone= 0;
- short val;
-
- /* find active bone to parent to */
- for (actbone = G.edbo.first; actbone; actbone=actbone->next) {
- if (EBONE_VISIBLE(arm, actbone)) {
- if (actbone->flag & BONE_ACTIVE)
- break;
- }
- }
- if (actbone == NULL) {
- error("Needs an active bone");
- return;
- }
-
- /* find selected bones */
- for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if ((ebone->flag & BONE_SELECTED) && (ebone != actbone)) {
- foundselbone++;
- if (ebone->parent != actbone) allchildbones= 1;
- }
- }
- }
- /* abort if no selected bones, and active bone doesn't have a parent to work with instead */
- if (foundselbone==0 && actbone->parent==NULL) {
- error("Need selected bone(s)");
- return;
- }
-
- /* 'Keep Offset' option is only displayed if it's likely to be useful */
- if (allchildbones)
- val= pupmenu("Make Parent%t|Connected%x1|Keep Offset%x2");
- else
- val= pupmenu("Make Parent%t|Connected%x1");
-
- if (val < 1) return;
-
- if (foundselbone==0 && actbone->parent) {
- /* When only the active bone is selected, and it has a parent,
- * connect it to the parent, as that is the only possible outcome.
- */
- bone_connect_to_existing_parent(actbone);
-
- if (arm->flag & ARM_MIRROR_EDIT) {
- flipbone = armature_bone_get_mirrored(actbone);
- if (flipbone)
- bone_connect_to_existing_parent(flipbone);
- }
- }
- else {
- /* loop through all editbones, parenting all selected bones to the active bone */
- for (selbone = G.edbo.first; selbone; selbone=selbone->next) {
- if (EBONE_VISIBLE(arm, selbone)) {
- if ((selbone->flag & BONE_SELECTED) && (selbone!=actbone)) {
- /* parent selbone to actbone */
- bone_connect_to_new_parent(selbone, actbone, val);
-
- if (arm->flag & ARM_MIRROR_EDIT) {
- /* - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone
- * (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
- * This is useful for arm-chains, for example parenting lower arm to upper arm
- * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
- * then just use actbone. Useful when doing upper arm to spine.
- */
- flipbone = armature_bone_get_mirrored(selbone);
- flippar = armature_bone_get_mirrored(actbone);
-
- if (flipbone) {
- if (flippar)
- bone_connect_to_new_parent(flipbone, flippar, val);
- else
- bone_connect_to_new_parent(flipbone, actbone, val);
- }
- }
- }
- }
- }
- }
-
- countall(); /* checks selection */
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- allqueue(REDRAWOOPS, 0);
- BIF_undo_push("Make Parent");
-
- return;
-}
-
-static void editbone_clear_parent(EditBone *ebone, int mode)
-{
- if (ebone->parent) {
- /* for nice selection */
- ebone->parent->flag &= ~(BONE_TIPSEL);
- }
-
- if (mode==1) ebone->parent= NULL;
- ebone->flag &= ~BONE_CONNECTED;
-}
-
-void clear_bone_parent(void)
-{
- bArmature *arm= G.obedit->data;
- EditBone *ebone;
- EditBone *flipbone = NULL;
- short val;
-
- val= pupmenu("Clear Parent%t|Clear Parent%x1|Disconnect Bone%x2");
- if (val<1) return;
-
- for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & BONE_SELECTED) {
- if (arm->flag & ARM_MIRROR_EDIT)
- flipbone = armature_bone_get_mirrored(ebone);
-
- if (flipbone)
- editbone_clear_parent(flipbone, val);
- editbone_clear_parent(ebone, val);
- }
- }
- }
-
- countall(); // checks selection
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- allqueue(REDRAWOOPS, 0);
- BIF_undo_push("Clear Parent");
-}
-
-
-static EditBone *editbone_name_exists (ListBase *ebones, char *name)
-{
- EditBone *eBone;
-
- if (ebones == NULL) ebones = &G.edbo;
-
- for (eBone=ebones->first; eBone; eBone=eBone->next) {
- if (!strcmp(name, eBone->name))
- return eBone;
- }
- return NULL;
-}
-
-/* note: there's a unique_bone_name() too! */
-void unique_editbone_name (ListBase *ebones, char *name)
-{
- char tempname[64];
- int number;
- char *dot;
-
- if (editbone_name_exists(ebones, name)) {
- /* Strip off the suffix, if it's a number */
- number= strlen(name);
- if (number && isdigit(name[number-1])) {
- dot= strrchr(name, '.'); // last occurrance
- if (dot)
- *dot=0;
- }
-
- for (number = 1; number <=999; number++) {
- sprintf(tempname, "%s.%03d", name, number);
- if (!editbone_name_exists(ebones, tempname)) {
- BLI_strncpy(name, tempname, 32);
- return;
- }
- }
- }
-}
-
-/* context; editmode armature */
-/* if forked && mirror-edit: makes two bones with flipped names */
-void extrude_armature(int forked)
-{
- bArmature *arm= G.obedit->data;
- EditBone *newbone, *ebone, *flipbone, *first=NULL;
- int a, totbone= 0, do_extrude;
-
- TEST_EDITARMATURE;
-
- /* since we allow root extrude too, we have to make sure selection is OK */
- for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & BONE_ROOTSEL) {
- if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
- if (ebone->parent->flag & BONE_TIPSEL)
- ebone->flag &= ~BONE_ROOTSEL;
- }
- }
- }
- }
-
- /* Duplicate the necessary bones */
- for (ebone = G.edbo.first; ((ebone) && (ebone!=first)); ebone=ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- /* we extrude per definition the tip */
- do_extrude= 0;
- if (ebone->flag & (BONE_TIPSEL|BONE_SELECTED))
- do_extrude= 1;
- else if (ebone->flag & BONE_ROOTSEL) {
- /* but, a bone with parent deselected we do the root... */
- if (ebone->parent && (ebone->parent->flag & BONE_TIPSEL));
- else do_extrude= 2;
- }
-
- if (do_extrude) {
- /* we re-use code for mirror editing... */
- flipbone= NULL;
- if (arm->flag & ARM_MIRROR_EDIT) {
- flipbone= armature_bone_get_mirrored(ebone);
- if (flipbone) {
- forked= 0; // we extrude 2 different bones
- if (flipbone->flag & (BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED))
- /* don't want this bone to be selected... */
- flipbone->flag &= ~(BONE_TIPSEL|BONE_SELECTED|BONE_ROOTSEL|BONE_ACTIVE);
- }
- if ((flipbone==NULL) && (forked))
- flipbone= ebone;
- }
-
- for (a=0; a<2; a++) {
- if (a==1) {
- if (flipbone==NULL)
- break;
- else {
- SWAP(EditBone *, flipbone, ebone);
- }
- }
-
- totbone++;
- newbone = MEM_callocN(sizeof(EditBone), "extrudebone");
-
- if (do_extrude==1) {
- VECCOPY (newbone->head, ebone->tail);
- VECCOPY (newbone->tail, newbone->head);
- newbone->parent = ebone;
-
- newbone->flag = ebone->flag & BONE_TIPSEL; // copies it, in case mirrored bone
-
- if (newbone->parent) newbone->flag |= BONE_CONNECTED;
- }
- else {
- VECCOPY(newbone->head, ebone->head);
- VECCOPY(newbone->tail, ebone->head);
- newbone->parent= ebone->parent;
-
- newbone->flag= BONE_TIPSEL;
-
- if (newbone->parent && (ebone->flag & BONE_CONNECTED)) {
- newbone->flag |= BONE_CONNECTED;
- }
- }
-
- newbone->weight= ebone->weight;
- newbone->dist= ebone->dist;
- newbone->xwidth= ebone->xwidth;
- newbone->zwidth= ebone->zwidth;
- newbone->ease1= ebone->ease1;
- newbone->ease2= ebone->ease2;
- newbone->rad_head= ebone->rad_tail; // dont copy entire bone...
- newbone->rad_tail= ebone->rad_tail;
- newbone->segments= 1;
- newbone->layer= ebone->layer;
-
- BLI_strncpy (newbone->name, ebone->name, 32);
-
- if (flipbone && forked) { // only set if mirror edit
- if (strlen(newbone->name)<30) {
- if (a==0) strcat(newbone->name, "_L");
- else strcat(newbone->name, "_R");
- }
- }
- unique_editbone_name(&G.edbo, newbone->name);
-
- /* Add the new bone to the list */
- BLI_addtail(&G.edbo, newbone);
- if (!first)
- first = newbone;
-
- /* restore ebone if we were flipping */
- if (a==1 && flipbone)
- SWAP(EditBone *, flipbone, ebone);
- }
- }
-
- /* Deselect the old bone */
- ebone->flag &= ~(BONE_TIPSEL|BONE_SELECTED|BONE_ROOTSEL|BONE_ACTIVE);
- }
- }
- /* if only one bone, make this one active */
- if (totbone==1 && first) first->flag |= BONE_ACTIVE;
-
- /* Transform the endpoints */
- countall(); // flushes selection!
- BIF_TransformSetUndo("Extrude");
- initTransform(TFM_TRANSLATION, CTX_NO_PET);
- Transform();
-
- allqueue(REDRAWBUTSEDIT, 0);
- allqueue(REDRAWBUTSOBJECT, 0);
- allqueue(REDRAWOOPS, 0);
-}
-
-/* context; editmode armature */
-void subdivide_armature(int numcuts)
-{
- bArmature *arm= G.obedit->data;
- EditBone *ebone, *newbone, *tbone, *mbone;
- int a, i;
-
- if (numcuts < 1) return;
-
- for (mbone = G.edbo.last; mbone; mbone= mbone->prev) {
- if (EBONE_VISIBLE(arm, mbone)) {
- if (mbone->flag & BONE_SELECTED) {
- for (i=numcuts+1; i>1; i--) {
- /* compute cut ratio first */
- float cutratio= 1/(float)i;
- float cutratioI= 1-cutratio;
-
- /* take care of mirrored stuff */
- for (a=0; a<2; a++) {
- float val1[3];
- float val2[3];
- float val3[3];
-
- /* try to find mirrored bone on a != 0 */
- if (a) {
- if (arm->flag & ARM_MIRROR_EDIT)
- ebone= armature_bone_get_mirrored(mbone);
- else
- ebone= NULL;
- }
- else
- ebone= mbone;
-
- if (ebone) {
- newbone= MEM_mallocN(sizeof(EditBone), "ebone subdiv");
- *newbone = *ebone;
- BLI_addtail(&G.edbo, newbone);
-
- /* calculate location of newbone->head */
- VECCOPY(val1, ebone->head);
- VECCOPY(val2, ebone->tail);
- VECCOPY(val3, newbone->head);
-
- val3[0]= val1[0]*cutratio+val2[0]*cutratioI;
- val3[1]= val1[1]*cutratio+val2[1]*cutratioI;
- val3[2]= val1[2]*cutratio+val2[2]*cutratioI;
-
- VECCOPY(newbone->head, val3);
- VECCOPY(newbone->tail, ebone->tail);
- VECCOPY(ebone->tail, newbone->head);
-
- newbone->rad_head= 0.5*(ebone->rad_head+ebone->rad_tail);
- ebone->rad_tail= newbone->rad_head;
-
- newbone->flag |= BONE_CONNECTED;
-
- unique_editbone_name (&G.edbo, newbone->name);
-
- /* correct parent bones */
- for (tbone = G.edbo.first; tbone; tbone=tbone->next) {
- if (tbone->parent==ebone)
- tbone->parent= newbone;
- }
- newbone->parent= ebone;
- }
- }
- }
- }
- }
- }
-
- if (numcuts==1) BIF_undo_push("Subdivide");
- else BIF_undo_push("Subdivide multi");
-}
-
-/* switch direction of bone chains */
-void switch_direction_armature (void)
-{
- bArmature *arm= (G.obedit) ? G.obedit->data : NULL;
- ListBase chains = {NULL, NULL};
- LinkData *chain;
-
- /* error checking paranoia */
- if (arm == NULL)
- return;
-
- /* get chains of bones (ends on chains) */
- chains_find_tips(&chains);
- if (chains.first == NULL) return;
-
- /* loop over chains, only considering selected and visible bones */
- for (chain= chains.first; chain; chain= chain->next) {
- EditBone *ebo, *child=NULL, *parent=NULL;
-
- /* loop over bones in chain */
- for (ebo= chain->data; ebo; ebo= parent) {
- /* parent is this bone's original parent
- * - we store this, as the next bone that is checked is this one
- * but the value of ebo->parent may change here...
- */
- parent= ebo->parent;
-
- /* only if selected and editable */
- if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) {
- /* swap head and tail coordinates */
- SWAP(float, ebo->head[0], ebo->tail[0]);
- SWAP(float, ebo->head[1], ebo->tail[1]);
- SWAP(float, ebo->head[2], ebo->tail[2]);
-
- /* do parent swapping:
- * - use 'child' as new parent
- * - connected flag is only set if points are coincidental
- */
- ebo->parent= child;
- if ((child) && VecEqual(ebo->head, child->tail))
- ebo->flag |= BONE_CONNECTED;
- else
- ebo->flag &= ~BONE_CONNECTED;
-
- /* get next bones
- * - child will become the new parent of next bone
- */
- child= ebo;
- }
- else {
- /* not swapping this bone, however, if its 'parent' got swapped, unparent us from it
- * as it will be facing in opposite direction
- */
- if ((parent) && (EBONE_VISIBLE(arm, parent) && EBONE_EDITABLE(parent))) {
- ebo->parent= NULL;
- ebo->flag &= ~BONE_CONNECTED;
- }
-
- /* get next bones
- * - child will become new parent of next bone (not swapping occurred,
- * so set to NULL to prevent infinite-loop)
- */
- child= NULL;
- }
- }
- }
-
- /* free chains */
- BLI_freelistN(&chains);
-
- BIF_undo_push("Switch Direction");
-}
-
-/* editbone alignment */
-
-/* helper to fix a ebone position if its parent has moved due to alignment*/
-static void fix_connected_bone(EditBone *ebone)
-{
- float diff[3];
-
- if (!(ebone->parent) || !(ebone->flag & BONE_CONNECTED) || VecEqual(ebone->parent->tail, ebone->head))
- return;
-
- /* if the parent has moved we translate child's head and tail accordingly*/
- VecSubf(diff, ebone->parent->tail, ebone->head);
- VecAddf(ebone->head, ebone->head, diff);
- VecAddf(ebone->tail, ebone->tail, diff);
- return;
-}
-
-/* helper to recursively find chains of connected bones starting at ebone and fix their position */
-static void fix_editbone_connected_children(EditBone *ebone)
-{
- EditBone *selbone;
-
- for (selbone = G.edbo.first; selbone; selbone=selbone->next) {
- if ((selbone->parent) && (selbone->parent == ebone) && (selbone->flag & BONE_CONNECTED)) {
- fix_connected_bone(selbone);
- fix_editbone_connected_children(selbone);
- }
- }
- return;
-}
-
-static void bone_align_to_bone(EditBone *selbone, EditBone *actbone)
-{
- float selboneaxis[3], actboneaxis[3], length;
-
- VecSubf(actboneaxis, actbone->tail, actbone->head);
- Normalize(actboneaxis);
-
- VecSubf(selboneaxis, selbone->tail, selbone->head);
- length = VecLength(selboneaxis);
-
- VecMulf(actboneaxis, length);
- VecAddf(selbone->tail, selbone->head, actboneaxis);
- selbone->roll = actbone->roll;
-
- /* if the bone being aligned has connected descendants they must be moved
- according to their parent new position, otherwise they would be left
- in an unconsistent state: connected but away from the parent*/
- fix_editbone_connected_children(selbone);
- return;
-}
-
-void align_selected_bones(void)
-{
- bArmature *arm= G.obedit->data;
- EditBone *actbone, *ebone, *selbone;
- EditBone *flipbone, *flippar;
- short allchildbones= 0, foundselbone= 0;
-
- /* find active bone to align to */
- for (actbone = G.edbo.first; actbone; actbone=actbone->next) {
- if (arm->layer & actbone->layer) {
- if (actbone->flag & BONE_ACTIVE)
- break;
- }
- }
- if (actbone == NULL) {
- error("Needs an active bone");
- return;
- }
-
- /* find selected bones */
- for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
- if (arm->layer & ebone->layer) {
- if ((ebone->flag & BONE_SELECTED) && (ebone != actbone)) {
- foundselbone++;
- if (ebone->parent != actbone) allchildbones= 1;
- }
- }
- }
- /* abort if no selected bones, and active bone doesn't have a parent to work with instead */
- if (foundselbone==0 && actbone->parent==NULL) {
- error("Need selected bone(s)");
- return;
- }
-
- if (foundselbone==0 && actbone->parent) {
- /* When only the active bone is selected, and it has a parent,
- * align it to the parent, as that is the only possible outcome.
- */
- bone_align_to_bone(actbone, actbone->parent);
-
- if (arm->flag & ARM_MIRROR_EDIT) {
- flipbone = armature_bone_get_mirrored(actbone);
- if (flipbone)
- bone_align_to_bone(flipbone, flipbone->parent);
- }
- }
- else {
- /* loop through all editbones, aligning all selected bones to the active bone */
- for (selbone = G.edbo.first; selbone; selbone=selbone->next) {
- if (arm->layer & selbone->layer) {
- if ((selbone->flag & BONE_SELECTED) && (selbone!=actbone)) {
- /* align selbone to actbone */
- bone_align_to_bone(selbone, actbone);
-
- if (arm->flag & ARM_MIRROR_EDIT) {
- /* - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone
- * (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
- * This is useful for arm-chains, for example parenting lower arm to upper arm
- * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
- * then just use actbone. Useful when doing upper arm to spine.
- */
- flipbone = armature_bone_get_mirrored(selbone);
- flippar = armature_bone_get_mirrored(actbone);
-
- if (flipbone) {
- if (flippar)
- bone_align_to_bone(flipbone, flippar);
- else
- bone_align_to_bone(flipbone, actbone);
- }
- }
- }
- }
- }
- }
-
- countall(); /* checks selection */
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- allqueue(REDRAWOOPS, 0);
- BIF_undo_push("Align bones");
-
- return;
-}
-
-/* ***************** Pose tools ********************* */
-
-void clear_armature(Object *ob, char mode)
-{
- bPoseChannel *pchan;
- bArmature *arm;
-
- arm= get_armature(ob);
- if (arm == NULL)
- return;
-
- /* only clear those channels that are not locked */
- for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
- if (pchan->bone && (pchan->bone->flag & BONE_SELECTED)) {
- if (arm->layer & pchan->bone->layer) {
- switch (mode) {
- case 'r':
- if (pchan->protectflag & (OB_LOCK_ROTX|OB_LOCK_ROTY|OB_LOCK_ROTZ)) {
- float eul[3], oldeul[3], quat1[4];
-
- QUATCOPY(quat1, pchan->quat);
- QuatToEul(pchan->quat, oldeul);
- eul[0]= eul[1]= eul[2]= 0.0f;
-
- if (pchan->protectflag & OB_LOCK_ROTX)
- eul[0]= oldeul[0];
- if (pchan->protectflag & OB_LOCK_ROTY)
- eul[1]= oldeul[1];
- if (pchan->protectflag & OB_LOCK_ROTZ)
- eul[2]= oldeul[2];
-
- EulToQuat(eul, pchan->quat);
- /* quaternions flip w sign to accumulate rotations correctly */
- if ((quat1[0]<0.0f && pchan->quat[0]>0.0f) || (quat1[0]>0.0f && pchan->quat[0]<0.0f)) {
- QuatMulf(pchan->quat, -1.0f);
- }
- }
- else {
- pchan->quat[1]=pchan->quat[2]=pchan->quat[3]=0.0F;
- pchan->quat[0]=1.0F;
- }
- break;
- case 'g':
- if ((pchan->protectflag & OB_LOCK_LOCX)==0)
- pchan->loc[0]= 0.0f;
- if ((pchan->protectflag & OB_LOCK_LOCY)==0)
- pchan->loc[1]= 0.0f;
- if ((pchan->protectflag & OB_LOCK_LOCZ)==0)
- pchan->loc[2]= 0.0f;
- break;
- case 's':
- if ((pchan->protectflag & OB_LOCK_SCALEX)==0)
- pchan->size[0]= 1.0f;
- if ((pchan->protectflag & OB_LOCK_SCALEY)==0)
- pchan->size[1]= 1.0f;
- if ((pchan->protectflag & OB_LOCK_SCALEZ)==0)
- pchan->size[2]= 1.0f;
- break;
-
- }
-
- /* the current values from IPO's may not be zero, so tag as unkeyed */
- pchan->bone->flag |= BONE_UNKEYED;
- }
- }
- }
-
- DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
- /* no update for this object, this will execute the action again */
- /* is weak... like for ipo editing which uses ctime now... */
- where_is_pose (ob);
- ob->recalc= 0;
-}
-
-/* helper for function below */
-static int clear_active_flag(Object *ob, Bone *bone, void *data)
-{
- bone->flag &= ~BONE_ACTIVE;
- return 0;
-}
-
-
-/* called from editview.c, for mode-less pose selection */
-int do_pose_selectbuffer(Base *base, unsigned int *buffer, short hits)
-{
- Object *ob= base->object;
- Bone *nearBone;
-
- if (!ob || !ob->pose) return 0;
-
- nearBone= get_bone_from_selectbuffer(base, buffer, hits, 1);
-
- if (nearBone) {
- bArmature *arm= ob->data;
-
- /* since we do unified select, we don't shift+select a bone if the armature object was not active yet */
- if (!(G.qual & LR_SHIFTKEY) || (base != BASACT)) {
- deselectall_posearmature(ob, 0, 0);
- nearBone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL|BONE_ACTIVE);
- select_actionchannel_by_name(ob->action, nearBone->name, 1);
- }
- else {
- if (nearBone->flag & BONE_SELECTED) {
- /* if not active, we make it active */
- if((nearBone->flag & BONE_ACTIVE)==0) {
- bone_looper(ob, arm->bonebase.first, NULL, clear_active_flag);
- nearBone->flag |= BONE_ACTIVE;
- }
- else {
- nearBone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL|BONE_ACTIVE);
- select_actionchannel_by_name(ob->action, nearBone->name, 0);
- }
- }
- else {
- bone_looper(ob, arm->bonebase.first, NULL, clear_active_flag);
-
- nearBone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL|BONE_ACTIVE);
- select_actionchannel_by_name(ob->action, nearBone->name, 1);
- }
- }
-
- /* in weightpaint we select the associated vertex group too */
- if (G.f & G_WEIGHTPAINT) {
- if (nearBone->flag & BONE_ACTIVE) {
- vertexgroup_select_by_name(OBACT, nearBone->name);
- DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
- }
- }
-
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWACTION, 0);
- allqueue(REDRAWIPO, 0); /* To force action/constraint ipo update */
- allqueue(REDRAWBUTSEDIT, 0);
- allqueue(REDRAWBUTSOBJECT, 0);
- allqueue(REDRAWOOPS, 0);
- }
-
- return nearBone!=NULL;
-}
-
-/* test==0: deselect all
- test==1: swap select (apply to all the opposite of current situation)
- test==2: only clear active tag
- test==3: swap select (no test / inverse selection status of all independently)
-*/
-void deselectall_posearmature (Object *ob, int test, int doundo)
-{
- bArmature *arm;
- bPoseChannel *pchan;
- int selectmode= 0;
-
- /* we call this from outliner too, but with OBACT set OK */
- if (ELEM(NULL, ob, ob->pose)) return;
- arm= get_armature(ob);
-
- /* Determine if we're selecting or deselecting */
- if (test==1) {
- for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
- if ((pchan->bone->layer & arm->layer) && !(pchan->bone->flag & BONE_HIDDEN_P)) {
- if (pchan->bone->flag & BONE_SELECTED)
- break;
- }
- }
-
- if (pchan == NULL)
- selectmode= 1;
- }
- else if (test == 2)
- selectmode= 2;
-
- /* Set the flags accordingly */
- for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
- if ((pchan->bone->layer & arm->layer) && !(pchan->bone->flag & BONE_HIDDEN_P)) {
- if (test==3) {
- pchan->bone->flag ^= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
- pchan->bone->flag &= ~BONE_ACTIVE;
- }
- else {
- if (selectmode==0) pchan->bone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL|BONE_ACTIVE);
- else if (selectmode==1) pchan->bone->flag |= BONE_SELECTED;
- else pchan->bone->flag &= ~BONE_ACTIVE;
- }
- }
- }
-
- /* action editor */
- if (test == 3) {
- deselect_actionchannels(ob->action, 2); /* inverts selection */
- }
- else {
- deselect_actionchannels(ob->action, 0); /* deselects for sure */
- if (selectmode == 1)
- deselect_actionchannels(ob->action, 1); /* swaps */
- }
-
- allqueue(REDRAWBUTSEDIT, 0);
- allqueue(REDRAWBUTSOBJECT, 0);
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWOOPS, 0);
- allqueue(REDRAWACTION, 0);
-
- countall();
-
- if (doundo) {
- if (selectmode==1) BIF_undo_push("Select All");
- else BIF_undo_push("Deselect All");
- }
-}
-
-
-int bone_looper(Object *ob, Bone *bone, void *data,
- int (*bone_func)(Object *, Bone *, void *))
-{
- /* We want to apply the function bone_func to every bone
- * in an armature -- feed bone_looper the first bone and
- * a pointer to the bone_func and watch it go!. The int count
- * can be useful for counting bones with a certain property
- * (e.g. skinnable)
- */
- int count = 0;
-
- if (bone) {
- /* only do bone_func if the bone is non null */
- count += bone_func(ob, bone, data);
-
- /* try to execute bone_func for the first child */
- count += bone_looper(ob, bone->childbase.first, data, bone_func);
-
- /* try to execute bone_func for the next bone at this
- * depth of the recursion.
- */
- count += bone_looper(ob, bone->next, data, bone_func);
- }
-
- return count;
-}
-
-
-static int bone_skinnable(Object *ob, Bone *bone, void *datap)
-{
- /* Bones that are deforming
- * are regarded to be "skinnable" and are eligible for
- * auto-skinning.
- *
- * This function performs 2 functions:
- *
- * a) It returns 1 if the bone is skinnable.
- * If we loop over all bones with this
- * function, we can count the number of
- * skinnable bones.
- * b) If the pointer data is non null,
- * it is treated like a handle to a
- * bone pointer -- the bone pointer
- * is set to point at this bone, and
- * the pointer the handle points to
- * is incremented to point to the
- * next member of an array of pointers
- * to bones. This way we can loop using
- * this function to construct an array of
- * pointers to bones that point to all
- * skinnable bones.
- */
- Bone ***hbone;
- int a, segments;
- struct { Object *armob; void *list; int heat; } *data = datap;
-
- if(!(G.f & G_WEIGHTPAINT) || !(bone->flag & BONE_HIDDEN_P)) {
- if (!(bone->flag & BONE_NO_DEFORM)) {
- if (data->heat && data->armob->pose && get_pose_channel(data->armob->pose, bone->name))
- segments = bone->segments;
- else
- segments = 1;
-
- if (data->list != NULL) {
- hbone = (Bone ***) &data->list;
-
- for (a=0; a<segments; a++) {
- **hbone = bone;
- ++*hbone;
- }
- }
- return segments;
- }
- }
- return 0;
-}
-
-static int add_defgroup_unique_bone(Object *ob, Bone *bone, void *data)
-{
- /* This group creates a vertex group to ob that has the
- * same name as bone (provided the bone is skinnable).
- * If such a vertex group aleady exist the routine exits.
- */
- if (!(bone->flag & BONE_NO_DEFORM)) {
- if (!get_named_vertexgroup(ob,bone->name)) {
- add_defgroup_name(ob, bone->name);
- return 1;
- }
- }
- return 0;
-}
-
-static int dgroup_skinnable(Object *ob, Bone *bone, void *datap)
-{
- /* Bones that are deforming
- * are regarded to be "skinnable" and are eligible for
- * auto-skinning.
- *
- * This function performs 2 functions:
- *
- * a) If the bone is skinnable, it creates
- * a vertex group for ob that has
- * the name of the skinnable bone
- * (if one doesn't exist already).
- * b) If the pointer data is non null,
- * it is treated like a handle to a
- * bDeformGroup pointer -- the
- * bDeformGroup pointer is set to point
- * to the deform group with the bone's
- * name, and the pointer the handle
- * points to is incremented to point to the
- * next member of an array of pointers
- * to bDeformGroups. This way we can loop using
- * this function to construct an array of
- * pointers to bDeformGroups, all with names
- * of skinnable bones.
- */
- bDeformGroup ***hgroup, *defgroup;
- int a, segments;
- struct { Object *armob; void *list; int heat; } *data= datap;
-
- if (!(G.f & G_WEIGHTPAINT) || !(bone->flag & BONE_HIDDEN_P)) {
- if (!(bone->flag & BONE_NO_DEFORM)) {
- if (data->heat && data->armob->pose && get_pose_channel(data->armob->pose, bone->name))
- segments = bone->segments;
- else
- segments = 1;
-
- if (!(defgroup = get_named_vertexgroup(ob, bone->name)))
- defgroup = add_defgroup_name(ob, bone->name);
-
- if (data->list != NULL) {
- hgroup = (bDeformGroup ***) &data->list;
-
- for (a=0; a<segments; a++) {
- **hgroup = defgroup;
- ++*hgroup;
- }
- }
- return segments;
- }
- }
- return 0;
-}
-
-static void add_vgroups__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
-{
- /* DerivedMesh mapFunc for getting final coords in weight paint mode */
-
- float (*verts)[3] = userData;
- VECCOPY(verts[index], co);
-}
-
-static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], int numbones, Bone **bonelist, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], int *selected, float scale)
-{
- /* Create vertex group weights from envelopes */
-
- Bone *bone;
- bDeformGroup *dgroup;
- float distance;
- int i, iflip, j;
-
- /* for each vertex in the mesh */
- for (i=0; i < mesh->totvert; i++) {
- iflip = (dgroupflip)? mesh_get_x_mirror_vert(ob, i): 0;
-
- /* for each skinnable bone */
- for (j=0; j < numbones; ++j) {
- if (!selected[j])
- continue;
-
- bone = bonelist[j];
- dgroup = dgrouplist[j];
-
- /* store the distance-factor from the vertex to the bone */
- distance = distfactor_to_bone (verts[i], root[j], tip[j],
- bone->rad_head * scale, bone->rad_tail * scale, bone->dist * scale);
-
- /* add the vert to the deform group if weight!=0.0 */
- if (distance!=0.0)
- add_vert_to_defgroup (ob, dgroup, i, distance, WEIGHT_REPLACE);
- else
- remove_vert_defgroup (ob, dgroup, i);
-
- /* do same for mirror */
- if (dgroupflip && dgroupflip[j] && iflip >= 0) {
- if (distance!=0.0)
- add_vert_to_defgroup (ob, dgroupflip[j], iflip, distance,
- WEIGHT_REPLACE);
- else
- remove_vert_defgroup (ob, dgroupflip[j], iflip);
- }
- }
- }
-}
-
-void add_verts_to_dgroups(Object *ob, Object *par, int heat, int mirror)
-{
- /* This functions implements the automatic computation of vertex group
- * weights, either through envelopes or using a heat equilibrium.
- *
- * This function can be called both when parenting a mesh to an armature,
- * or in weightpaint + posemode. In the latter case selection is taken
- * into account and vertex weights can be mirrored.
- *
- * The mesh vertex positions used are either the final deformed coords
- * from the derivedmesh in weightpaint mode, the final subsurf coords
- * when parenting, or simply the original mesh coords.
- */
-
- bArmature *arm;
- Bone **bonelist, *bone;
- bDeformGroup **dgrouplist, **dgroupflip;
- bDeformGroup *dgroup, *curdg;
- bPoseChannel *pchan;
- Mesh *mesh;
- Mat4 *bbone = NULL;
- float (*root)[3], (*tip)[3], (*verts)[3];
- int *selected;
- int numbones, vertsfilled = 0, i, j, segments = 0;
- int wpmode = (G.f & G_WEIGHTPAINT);
- struct { Object *armob; void *list; int heat; } looper_data;
-
- /* If the parent object is not an armature exit */
- arm = get_armature(par);
- if (!arm)
- return;
-
- looper_data.armob = par;
- looper_data.heat= heat;
- looper_data.list= NULL;
-
- /* count the number of skinnable bones */
- numbones = bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable);
-
- if (numbones == 0)
- return;
-
- /* create an array of pointer to bones that are skinnable
- * and fill it with all of the skinnable bones */
- bonelist = MEM_callocN(numbones*sizeof(Bone *), "bonelist");
- looper_data.list= bonelist;
- bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable);
-
- /* create an array of pointers to the deform groups that
- * coorespond to the skinnable bones (creating them
- * as necessary. */
- dgrouplist = MEM_callocN(numbones*sizeof(bDeformGroup *), "dgrouplist");
- dgroupflip = MEM_callocN(numbones*sizeof(bDeformGroup *), "dgroupflip");
-
- looper_data.list= dgrouplist;
- bone_looper(ob, arm->bonebase.first, &looper_data, dgroup_skinnable);
-
- /* create an array of root and tip positions transformed into
- * global coords */
- root = MEM_callocN(numbones*sizeof(float)*3, "root");
- tip = MEM_callocN(numbones*sizeof(float)*3, "tip");
- selected = MEM_callocN(numbones*sizeof(int), "selected");
-
- for (j=0; j < numbones; ++j) {
- bone = bonelist[j];
- dgroup = dgrouplist[j];
-
- /* handle bbone */
- if (heat) {
- if (segments == 0) {
- segments = 1;
- bbone = NULL;
-
- if ((par->pose) && (pchan=get_pose_channel(par->pose, bone->name))) {
- if (bone->segments > 1) {
- segments = bone->segments;
- bbone = b_bone_spline_setup(pchan, 1);
- }
- }
- }
-
- segments--;
- }
-
- /* compute root and tip */
- if (bbone) {
- VECCOPY(root[j], bbone[segments].mat[3]);
- Mat4MulVecfl(bone->arm_mat, root[j]);
- if ((segments+1) < bone->segments) {
- VECCOPY(tip[j], bbone[segments+1].mat[3])
- Mat4MulVecfl(bone->arm_mat, tip[j]);
- }
- else
- VECCOPY(tip[j], bone->arm_tail)
- }
- else {
- VECCOPY(root[j], bone->arm_head);
- VECCOPY(tip[j], bone->arm_tail);
- }
-
- Mat4MulVecfl(par->obmat, root[j]);
- Mat4MulVecfl(par->obmat, tip[j]);
-
- /* set selected */
- if (wpmode) {
- if ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))
- selected[j] = 1;
- }
- else
- selected[j] = 1;
-
- /* find flipped group */
- if (mirror) {
- char name[32];
-
- BLI_strncpy(name, dgroup->name, 32);
- // 0 = don't strip off number extensions
- bone_flip_name(name, 0);
-
- for (curdg = ob->defbase.first; curdg; curdg=curdg->next) {
- if (!strcmp(curdg->name, name))
- break;
- }
-
- dgroupflip[j] = curdg;
- }
- }
-
- /* create verts */
- mesh = (Mesh*)ob->data;
- verts = MEM_callocN(mesh->totvert*sizeof(*verts), "closestboneverts");
-
- if (wpmode) {
- /* if in weight paint mode, use final verts from derivedmesh */
- DerivedMesh *dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH);
-
- if (dm->foreachMappedVert) {
- dm->foreachMappedVert(dm, add_vgroups__mapFunc, (void*)verts);
- vertsfilled = 1;
- }
-
- dm->release(dm);
- }
- else if (modifiers_findByType(ob, eModifierType_Subsurf)) {
- /* is subsurf on? Lets use the verts on the limit surface then.
- * = same amount of vertices as mesh, but vertices moved to the
- * subsurfed position, like for 'optimal'. */
- subsurf_calculate_limit_positions(mesh, verts);
- vertsfilled = 1;
- }
-
- /* transform verts to global space */
- for (i=0; i < mesh->totvert; i++) {
- if (!vertsfilled)
- VECCOPY(verts[i], mesh->mvert[i].co)
- Mat4MulVecfl(ob->obmat, verts[i]);
- }
-
- /* compute the weights based on gathered vertices and bones */
- if (heat) {
- heat_bone_weighting(ob, mesh, verts, numbones, dgrouplist, dgroupflip,
- root, tip, selected);
- }
- else {
- envelope_bone_weighting(ob, mesh, verts, numbones, bonelist, dgrouplist,
- dgroupflip, root, tip, selected, Mat4ToScalef(par->obmat));
- }
-
- /* free the memory allocated */
- MEM_freeN(bonelist);
- MEM_freeN(dgrouplist);
- MEM_freeN(dgroupflip);
- MEM_freeN(root);
- MEM_freeN(tip);
- MEM_freeN(selected);
- MEM_freeN(verts);
-}
-
-void create_vgroups_from_armature(Object *ob, Object *par)
-{
- /* Lets try to create some vertex groups
- * based on the bones of the parent armature.
- */
-
- bArmature *arm;
- short mode;
-
- /* If the parent object is not an armature exit */
- arm = get_armature(par);
- if (!arm)
- return;
-
- /* Prompt the user on whether/how they want the vertex groups
- * added to the child mesh */
- mode= pupmenu("Create Vertex Groups? %t|"
- "Don't Create Groups %x1|"
- "Name Groups %x2|"
- "Create From Envelopes %x3|"
- "Create From Bone Heat %x4|");
- switch (mode) {
- case 2:
- /* Traverse the bone list, trying to create empty vertex
- * groups cooresponding to the bone.
- */
- bone_looper(ob, arm->bonebase.first, NULL,
- add_defgroup_unique_bone);
- if (ob->type == OB_MESH)
- create_dverts(ob->data);
-
- break;
-
- case 3:
- case 4:
- /* Traverse the bone list, trying to create vertex groups
- * that are populated with the vertices for which the
- * bone is closest.
- */
- add_verts_to_dgroups(ob, par, (mode == 4), 0);
- break;
- }
-}
-
-static int hide_selected_pose_bone(Object *ob, Bone *bone, void *ptr)
-{
- bArmature *arm= ob->data;
-
- if (arm->layer & bone->layer) {
- if (bone->flag & BONE_SELECTED) {
- bone->flag |= BONE_HIDDEN_P;
- bone->flag &= ~(BONE_SELECTED|BONE_ACTIVE);
- }
- }
- return 0;
-}
-
-/* active object is armature */
-void hide_selected_pose_bones(void)
-{
- bArmature *arm= OBACT->data;
-
- if (!arm)
- return;
-
- bone_looper(OBACT, arm->bonebase.first, NULL,
- hide_selected_pose_bone);
-
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- allqueue(REDRAWACTION, 0);
- BIF_undo_push("Hide Bones");
-}
-
-static int hide_unselected_pose_bone(Object *ob, Bone *bone, void *ptr)
-{
- bArmature *arm= ob->data;
-
- if (arm->layer & bone->layer) {
- // hrm... typo here?
- if (~bone->flag & BONE_SELECTED) {
- bone->flag |= BONE_HIDDEN_P;
- bone->flag &= ~BONE_ACTIVE;
- }
- }
- return 0;
-}
-
-/* active object is armature */
-void hide_unselected_pose_bones(void)
-{
- bArmature *arm;
-
- arm=get_armature(OBACT);
-
- if (!arm)
- return;
-
- bone_looper(OBACT, arm->bonebase.first, NULL,
- hide_unselected_pose_bone);
-
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- allqueue(REDRAWACTION, 0);
- BIF_undo_push("Hide Unselected Bone");
-}
-
-static int show_pose_bone(Object *ob, Bone *bone, void *ptr)
-{
- bArmature *arm= ob->data;
-
- if (arm->layer & bone->layer) {
- if (bone->flag & BONE_HIDDEN_P) {
- bone->flag &= ~BONE_HIDDEN_P;
- bone->flag |= BONE_SELECTED;
- }
- }
-
- return 0;
-}
-
-/* active object is armature in posemode */
-void show_all_pose_bones(void)
-{
- bArmature *arm;
-
- arm=get_armature(OBACT);
-
- if (!arm)
- return;
-
- bone_looper(OBACT, arm->bonebase.first, NULL,
- show_pose_bone);
-
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- allqueue(REDRAWACTION, 0);
- BIF_undo_push("Reveal Bones");
-}
-
-
-/* ************* RENAMING DISASTERS ************ */
-
-/* note: there's a unique_editbone_name() too! */
-void unique_bone_name (bArmature *arm, char *name)
-{
- char tempname[64];
- int number;
- char *dot;
-
- if (get_named_bone(arm, name)) {
-
- /* Strip off the suffix, if it's a number */
- number= strlen(name);
- if(number && isdigit(name[number-1])) {
- dot= strrchr(name, '.'); // last occurrance
- if (dot)
- *dot=0;
- }
-
- for (number = 1; number <=999; number++) {
- sprintf (tempname, "%s.%03d", name, number);
- if (!get_named_bone(arm, tempname)) {
- BLI_strncpy (name, tempname, 32);
- return;
- }
- }
- }
-}
-
-#define MAXBONENAME 32
-/* helper call for armature_bone_rename */
-static void constraint_bone_name_fix(Object *ob, ListBase *conlist, char *oldname, char *newname)
-{
- bConstraint *curcon;
- bConstraintTarget *ct;
-
- for (curcon = conlist->first; curcon; curcon=curcon->next) {
- bConstraintTypeInfo *cti= constraint_get_typeinfo(curcon);
- ListBase targets = {NULL, NULL};
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(curcon, &targets);
-
- for (ct= targets.first; ct; ct= ct->next) {
- if (ct->tar == ob) {
- if (!strcmp(ct->subtarget, oldname) )
- BLI_strncpy(ct->subtarget, newname, MAXBONENAME);
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(curcon, &targets, 0);
- }
- }
-}
-
-/* called by UI for renaming a bone */
-/* warning: make sure the original bone was not renamed yet! */
-/* seems messy, but thats what you get with not using pointers but channel names :) */
-void armature_bone_rename(bArmature *arm, char *oldnamep, char *newnamep)
-{
- Object *ob;
- Ipo *ipo;
- char newname[MAXBONENAME];
- char oldname[MAXBONENAME];
-
- /* names better differ! */
- if(strncmp(oldnamep, newnamep, MAXBONENAME)) {
-
- /* we alter newname string... so make copy */
- BLI_strncpy(newname, newnamep, MAXBONENAME);
- /* we use oldname for search... so make copy */
- BLI_strncpy(oldname, oldnamep, MAXBONENAME);
-
- /* now check if we're in editmode, we need to find the unique name */
- if ((G.obedit) && (G.obedit->data==arm)) {
- EditBone *eBone;
-
- eBone= editbone_name_exists(&G.edbo, oldname);
- if (eBone) {
- unique_editbone_name(&G.edbo, newname);
- BLI_strncpy(eBone->name, newname, MAXBONENAME);
- }
- else return;
- }
- else {
- Bone *bone= get_named_bone(arm, oldname);
-
- if (bone) {
- unique_bone_name (arm, newname);
- BLI_strncpy(bone->name, newname, MAXBONENAME);
- }
- else return;
- }
-
- /* do entire dbase - objects */
- for (ob= G.main->object.first; ob; ob= ob->id.next) {
- /* we have the object using the armature */
- if (arm==ob->data) {
- Object *cob;
- bAction *act;
- bActionChannel *achan;
- bActionStrip *strip;
-
- /* Rename action channel if necessary */
- act = ob->action;
- if (act && !act->id.lib) {
- /* Find the appropriate channel */
- achan= get_action_channel(act, oldname);
- if (achan)
- BLI_strncpy(achan->name, newname, MAXBONENAME);
- }
-
- /* Rename the pose channel, if it exists */
- if (ob->pose) {
- bPoseChannel *pchan = get_pose_channel(ob->pose, oldname);
- if (pchan)
- BLI_strncpy(pchan->name, newname, MAXBONENAME);
- }
-
- /* check all nla-strips too */
- for (strip= ob->nlastrips.first; strip; strip= strip->next) {
- /* Rename action channel if necessary */
- act = strip->act;
- if (act && !act->id.lib) {
- /* Find the appropriate channel */
- achan= get_action_channel(act, oldname);
- if (achan)
- BLI_strncpy(achan->name, newname, MAXBONENAME);
- }
- }
-
- /* Update any object constraints to use the new bone name */
- for (cob= G.main->object.first; cob; cob= cob->id.next) {
- if (cob->constraints.first)
- constraint_bone_name_fix(ob, &cob->constraints, oldname, newname);
- if (cob->pose) {
- bPoseChannel *pchan;
- for (pchan = cob->pose->chanbase.first; pchan; pchan=pchan->next) {
- constraint_bone_name_fix(ob, &pchan->constraints, oldname, newname);
- }
- }
- }
- }
-
- /* See if an object is parented to this armature */
- if (ob->parent && (ob->parent->data == arm)) {
- if (ob->partype==PARBONE) {
- /* bone name in object */
- if (!strcmp(ob->parsubstr, oldname))
- BLI_strncpy(ob->parsubstr, newname, MAXBONENAME);
- }
- }
-
- if (modifiers_usesArmature(ob, arm)) {
- bDeformGroup *dg;
- /* bone name in defgroup */
- for (dg=ob->defbase.first; dg; dg=dg->next) {
- if (!strcmp(dg->name, oldname))
- BLI_strncpy(dg->name, newname, MAXBONENAME);
- }
- }
- }
-
- /* do entire db - ipo's for the drivers */
- for (ipo= G.main->ipo.first; ipo; ipo= ipo->id.next) {
- IpoCurve *icu;
-
- /* check each curve's driver */
- for (icu= ipo->curve.first; icu; icu= icu->next) {
- IpoDriver *icd= icu->driver;
-
- if ((icd) && (icd->ob)) {
- ob= icd->ob;
-
- if (icu->driver->type == IPO_DRIVER_TYPE_NORMAL) {
- if (!strcmp(oldname, icd->name))
- BLI_strncpy(icd->name, newname, MAXBONENAME);
- }
- else {
- /* TODO: pydrivers need to be treated differently */
- }
- }
- }
- }
- }
-}
-
-/* context editmode object */
-void armature_flip_names(void)
-{
- bArmature *arm= G.obedit->data;
- EditBone *ebone;
- char newname[32];
-
- for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
- if (arm->layer & ebone->layer) {
- if (ebone->flag & BONE_SELECTED) {
- BLI_strncpy(newname, ebone->name, sizeof(newname));
- bone_flip_name(newname, 1); // 1 = do strip off number extensions
- armature_bone_rename(G.obedit->data, ebone->name, newname);
- }
- }
- }
-
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- allqueue(REDRAWBUTSOBJECT, 0);
- allqueue(REDRAWACTION, 0);
- allqueue(REDRAWOOPS, 0);
- BIF_undo_push("Flip names");
-}
-
-/* context: edtimode armature */
-void armature_autoside_names(short axis)
-{
- bArmature *arm= G.obedit->data;
- EditBone *ebone;
- char newname[32];
-
- for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
- if (arm->layer & ebone->layer) {
- if (ebone->flag & BONE_SELECTED) {
- BLI_strncpy(newname, ebone->name, sizeof(newname));
- bone_autoside_name(newname, 1, axis, ebone->head[axis], ebone->tail[axis]);
- armature_bone_rename(G.obedit->data, ebone->name, newname);
- }
- }
- }
-
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- allqueue(REDRAWBUTSOBJECT, 0);
- allqueue(REDRAWACTION, 0);
- allqueue(REDRAWOOPS, 0);
- BIF_undo_push("Auto-side name");
-}
-
-/* context: editmode armature */
-EditBone *armature_bone_get_mirrored(EditBone *ebo)
-{
- EditBone *eboflip= NULL;
- char name[32];
-
- BLI_strncpy(name, ebo->name, sizeof(name));
- bone_flip_name(name, 0); // 0 = don't strip off number extensions
-
- for (eboflip=G.edbo.first; eboflip; eboflip=eboflip->next) {
- if (ebo != eboflip) {
- if (!strcmp (name, eboflip->name))
- break;
- }
- }
-
- return eboflip;
-}
-
-/* if editbone (partial) selected, copy data */
-/* context; editmode armature, with mirror editing enabled */
-void transform_armature_mirror_update(void)
-{
- EditBone *ebo, *eboflip;
-
- for (ebo=G.edbo.first; ebo; ebo=ebo->next) {
- /* no layer check, correct mirror is more important */
- if (ebo->flag & (BONE_TIPSEL|BONE_ROOTSEL)) {
- eboflip= armature_bone_get_mirrored(ebo);
-
- if (eboflip) {
- /* we assume X-axis flipping for now */
- if (ebo->flag & BONE_TIPSEL) {
- EditBone *children;
-
- eboflip->tail[0]= -ebo->tail[0];
- eboflip->tail[1]= ebo->tail[1];
- eboflip->tail[2]= ebo->tail[2];
- eboflip->rad_tail= ebo->rad_tail;
-
- /* Also move connected children, in case children's name aren't mirrored properly */
- for (children=G.edbo.first; children; children=children->next) {
- if (children->parent == eboflip && children->flag & BONE_CONNECTED) {
- VECCOPY(children->head, eboflip->tail);
- children->rad_head = ebo->rad_tail;
- }
- }
- }
- if (ebo->flag & BONE_ROOTSEL) {
- eboflip->head[0]= -ebo->head[0];
- eboflip->head[1]= ebo->head[1];
- eboflip->head[2]= ebo->head[2];
- eboflip->rad_head= ebo->rad_head;
-
- /* Also move connected parent, in case parent's name isn't mirrored properly */
- if (eboflip->parent && eboflip->flag & BONE_CONNECTED)
- {
- EditBone *parent = eboflip->parent;
- VECCOPY(parent->tail, eboflip->head);
- parent->rad_tail = ebo->rad_head;
- }
- }
- if (ebo->flag & BONE_SELECTED) {
- eboflip->dist= ebo->dist;
- eboflip->roll= -ebo->roll;
- eboflip->xwidth= ebo->xwidth;
- eboflip->zwidth= ebo->zwidth;
- }
- }
- }
- }
-}
-
-
-/*****************************************************************************************************/
-/*************************************** SKELETON GENERATOR ******************************************/
-/*****************************************************************************************************/
-
-
-
-/**************************************** SUBDIVISION ALGOS ******************************************/
-
-EditBone * subdivideByAngle(ReebArc *arc, ReebNode *head, ReebNode *tail)
-{
- EditBone *lastBone = NULL;
- if (G.scene->toolsettings->skgen_options & SKGEN_CUT_ANGLE)
- {
- ReebArcIterator iter;
- EmbedBucket *current = NULL;
- EmbedBucket *previous = NULL;
- EditBone *child = NULL;
- EditBone *parent = NULL;
- EditBone *root = NULL;
- float angleLimit = (float)cos(G.scene->toolsettings->skgen_angle_limit * M_PI / 180.0f);
-
- parent = add_editbone("Bone");
- parent->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
- VECCOPY(parent->head, head->p);
-
- root = parent;
-
- for (initArcIterator(&iter, arc, head), previous = nextBucket(&iter), current = nextBucket(&iter);
- current;
- previous = current, current = nextBucket(&iter))
- {
- float vec1[3], vec2[3];
- float len1, len2;
-
- VecSubf(vec1, previous->p, parent->head);
- VecSubf(vec2, current->p, previous->p);
-
- len1 = Normalize(vec1);
- len2 = Normalize(vec2);
-
- if (len1 > 0.0f && len2 > 0.0f && Inpf(vec1, vec2) < angleLimit)
- {
- VECCOPY(parent->tail, previous->p);
-
- child = add_editbone("Bone");
- VECCOPY(child->head, parent->tail);
- child->parent = parent;
- child->flag |= BONE_CONNECTED|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
-
- parent = child; /* new child is next parent */
- }
- }
- VECCOPY(parent->tail, tail->p);
-
- /* If the bone wasn't subdivided, delete it and return NULL
- * to let subsequent subdivision methods do their thing.
- * */
- if (parent == root)
- {
- delete_bone(parent);
- parent = NULL;
- }
-
- lastBone = parent; /* set last bone in the chain */
- }
-
- return lastBone;
-}
-
-float calcVariance(ReebArc *arc, int start, int end, float v0[3], float n[3])
-{
- int len = 2 + abs(end - start);
-
- if (len > 2)
- {
- ReebArcIterator iter;
- EmbedBucket *bucket = NULL;
- float avg_t = 0.0f;
- float s_t = 0.0f;
- float s_xyz = 0.0f;
-
- /* First pass, calculate average */
- for (initArcIterator2(&iter, arc, start, end), bucket = nextBucket(&iter);
- bucket;
- bucket = nextBucket(&iter))
- {
- float v[3];
-
- VecSubf(v, bucket->p, v0);
- avg_t += Inpf(v, n);
- }
-
- avg_t /= Inpf(n, n);
- avg_t += 1.0f; /* adding start (0) and end (1) values */
- avg_t /= len;
-
- /* Second pass, calculate s_xyz and s_t */
- for (initArcIterator2(&iter, arc, start, end), bucket = nextBucket(&iter);
- bucket;
- bucket = nextBucket(&iter))
- {
- float v[3], d[3];
- float dt;
-
- VecSubf(v, bucket->p, v0);
- Projf(d, v, n);
- VecSubf(v, v, d);
-
- dt = VecLength(d) - avg_t;
-
- s_t += dt * dt;
- s_xyz += Inpf(v, v);
- }
-
- /* adding start(0) and end(1) values to s_t */
- s_t += (avg_t * avg_t) + (1 - avg_t) * (1 - avg_t);
-
- return s_xyz / s_t;
- }
- else
- {
- return 0;
- }
-}
-
-float calcDistance(ReebArc *arc, int start, int end, float head[3], float tail[3])
-{
- ReebArcIterator iter;
- EmbedBucket *bucket = NULL;
- float max_dist = 0;
-
- /* calculate maximum distance */
- for (initArcIterator2(&iter, arc, start, end), bucket = nextBucket(&iter);
- bucket;
- bucket = nextBucket(&iter))
- {
- float v1[3], v2[3], c[3];
- float dist;
-
- VecSubf(v1, head, tail);
- VecSubf(v2, bucket->p, tail);
-
- Crossf(c, v1, v2);
-
- dist = Inpf(c, c) / Inpf(v1, v1);
-
- max_dist = dist > max_dist ? dist : max_dist;
- }
-
-
- return max_dist;
-}
-
-EditBone * subdivideByCorrelation(ReebArc *arc, ReebNode *head, ReebNode *tail)
-{
- ReebArcIterator iter;
- float n[3];
- float ADAPTIVE_THRESHOLD = G.scene->toolsettings->skgen_correlation_limit;
- EditBone *lastBone = NULL;
-
- /* init iterator to get start and end from head */
- initArcIterator(&iter, arc, head);
-
- /* Calculate overall */
- VecSubf(n, arc->buckets[iter.end].p, head->p);
-
- if (G.scene->toolsettings->skgen_options & SKGEN_CUT_CORRELATION)
- {
- EmbedBucket *bucket = NULL;
- EmbedBucket *previous = NULL;
- EditBone *child = NULL;
- EditBone *parent = NULL;
- float normal[3] = {0, 0, 0};
- float avg_normal[3];
- int total = 0;
- int boneStart = iter.start;
-
- parent = add_editbone("Bone");
- parent->flag = BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
- VECCOPY(parent->head, head->p);
-
- for (previous = nextBucket(&iter), bucket = nextBucket(&iter);
- bucket;
- previous = bucket, bucket = nextBucket(&iter))
- {
- float btail[3];
- float value = 0;
-
- if (G.scene->toolsettings->skgen_options & SKGEN_STICK_TO_EMBEDDING)
- {
- VECCOPY(btail, bucket->p);
- }
- else
- {
- float length;
-
- /* Calculate normal */
- VecSubf(n, bucket->p, parent->head);
- length = Normalize(n);
-
- total += 1;
- VecAddf(normal, normal, n);
- VECCOPY(avg_normal, normal);
- VecMulf(avg_normal, 1.0f / total);
-
- VECCOPY(btail, avg_normal);
- VecMulf(btail, length);
- VecAddf(btail, btail, parent->head);
- }
-
- if (G.scene->toolsettings->skgen_options & SKGEN_ADAPTIVE_DISTANCE)
- {
- value = calcDistance(arc, boneStart, iter.index, parent->head, btail);
- }
- else
- {
- float n[3];
-
- VecSubf(n, btail, parent->head);
- value = calcVariance(arc, boneStart, iter.index, parent->head, n);
- }
-
- if (value > ADAPTIVE_THRESHOLD)
- {
- VECCOPY(parent->tail, btail);
-
- child = add_editbone("Bone");
- VECCOPY(child->head, parent->tail);
- child->parent = parent;
- child->flag |= BONE_CONNECTED|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
-
- parent = child; // new child is next parent
- boneStart = iter.index; // start from end
-
- normal[0] = normal[1] = normal[2] = 0;
- total = 0;
- }
- }
-
- VECCOPY(parent->tail, tail->p);
-
- lastBone = parent; /* set last bone in the chain */
- }
-
- return lastBone;
-}
-
-float arcLengthRatio(ReebArc *arc)
-{
- float arcLength = 0.0f;
- float embedLength = 0.0f;
- int i;
-
- arcLength = VecLenf(arc->head->p, arc->tail->p);
-
- if (arc->bcount > 0)
- {
- /* Add the embedding */
- for ( i = 1; i < arc->bcount; i++)
- {
- embedLength += VecLenf(arc->buckets[i - 1].p, arc->buckets[i].p);
- }
- /* Add head and tail -> embedding vectors */
- embedLength += VecLenf(arc->head->p, arc->buckets[0].p);
- embedLength += VecLenf(arc->tail->p, arc->buckets[arc->bcount - 1].p);
- }
- else
- {
- embedLength = arcLength;
- }
-
- return embedLength / arcLength;
-}
-
-EditBone * subdivideByLength(ReebArc *arc, ReebNode *head, ReebNode *tail)
-{
- EditBone *lastBone = NULL;
- if ((G.scene->toolsettings->skgen_options & SKGEN_CUT_LENGTH) &&
- arcLengthRatio(arc) >= G.scene->toolsettings->skgen_length_ratio)
- {
- ReebArcIterator iter;
- EmbedBucket *bucket = NULL;
- EmbedBucket *previous = NULL;
- EditBone *child = NULL;
- EditBone *parent = NULL;
- float lengthLimit = G.scene->toolsettings->skgen_length_limit;
- int same = 0;
-
- parent = add_editbone("Bone");
- parent->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
- VECCOPY(parent->head, head->p);
-
- initArcIterator(&iter, arc, head);
-
- bucket = nextBucket(&iter);
-
- while (bucket != NULL)
- {
- float *vec0 = NULL;
- float *vec1 = bucket->p;
-
- /* first bucket. Previous is head */
- if (previous == NULL)
- {
- vec0 = head->p;
- }
- /* Previous is a valid bucket */
- else
- {
- vec0 = previous->p;
- }
-
- /* If lengthLimit hits the current segment */
- if (VecLenf(vec1, parent->head) > lengthLimit)
- {
- if (same == 0)
- {
- float dv[3], off[3];
- float a, b, c, f;
-
- /* Solve quadratic distance equation */
- VecSubf(dv, vec1, vec0);
- a = Inpf(dv, dv);
-
- VecSubf(off, vec0, parent->head);
- b = 2 * Inpf(dv, off);
-
- c = Inpf(off, off) - (lengthLimit * lengthLimit);
-
- f = (-b + (float)sqrt(b * b - 4 * a * c)) / (2 * a);
-
- //printf("a %f, b %f, c %f, f %f\n", a, b, c, f);
-
- if (isnan(f) == 0 && f < 1.0f)
- {
- VECCOPY(parent->tail, dv);
- VecMulf(parent->tail, f);
- VecAddf(parent->tail, parent->tail, vec0);
- }
- else
- {
- VECCOPY(parent->tail, vec1);
- }
- }
- else
- {
- float dv[3];
-
- VecSubf(dv, vec1, vec0);
- Normalize(dv);
-
- VECCOPY(parent->tail, dv);
- VecMulf(parent->tail, lengthLimit);
- VecAddf(parent->tail, parent->tail, parent->head);
- }
-
- child = add_editbone("Bone");
- VECCOPY(child->head, parent->tail);
- child->parent = parent;
- child->flag |= BONE_CONNECTED|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
-
- parent = child; // new child is next parent
-
- same = 1; // mark as same
- }
- else
- {
- previous = bucket;
- bucket = nextBucket(&iter);
- same = 0; // Reset same
- }
- }
- VECCOPY(parent->tail, tail->p);
-
- lastBone = parent; /* set last bone in the chain */
- }
-
- return lastBone;
-}
-
-/***************************************** MAIN ALGORITHM ********************************************/
-
-void generateSkeletonFromReebGraph(ReebGraph *rg)
-{
- GHash *arcBoneMap = NULL;
- ReebArc *arc = NULL;
- ReebNode *node = NULL;
- Object *src = NULL;
- Object *dst = NULL;
-
- src = BASACT->object;
-
- if (G.obedit != NULL)
- {
- exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR); // freedata, and undo
- }
-
- dst = add_object(OB_ARMATURE);
- base_init_from_view3d(BASACT, G.vd);
- G.obedit= BASACT->object;
-
- /* Copy orientation from source */
- VECCOPY(dst->loc, src->obmat[3]);
- Mat4ToEul(src->obmat, dst->rot);
- Mat4ToSize(src->obmat, dst->size);
-
- where_is_object(G.obedit);
-
- make_editArmature();
-
- arcBoneMap = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
-
- BLI_markdownSymmetry((BGraph*)rg, rg->nodes.first, G.scene->toolsettings->skgen_symmetry_limit);
-
- for (arc = rg->arcs.first; arc; arc = arc->next)
- {
- EditBone *lastBone = NULL;
- ReebNode *head, *tail;
- int i;
-
- /* Find out the direction of the arc through simple heuristics (in order of priority) :
- *
- * 1- Arcs on primary symmetry axis (symmetry == 1) point up (head: high weight -> tail: low weight)
- * 2- Arcs starting on a primary axis point away from it (head: node on primary axis)
- * 3- Arcs point down (head: low weight -> tail: high weight)
- *
- * Finally, the arc direction is stored in its flag: 1 (low -> high), -1 (high -> low)
- */
-
- /* if arc is a symmetry axis, internal bones go up the tree */
- if (arc->symmetry_level == 1 && arc->tail->degree != 1)
- {
- head = arc->tail;
- tail = arc->head;
-
- arc->flag = -1; /* mark arc direction */
- }
- /* Bones point AWAY from the symmetry axis */
- else if (arc->head->symmetry_level == 1)
- {
- head = arc->head;
- tail = arc->tail;
-
- arc->flag = 1; /* mark arc direction */
- }
- else if (arc->tail->symmetry_level == 1)
- {
- head = arc->tail;
- tail = arc->head;
-
- arc->flag = -1; /* mark arc direction */
- }
- /* otherwise, always go from low weight to high weight */
- else
- {
- head = arc->head;
- tail = arc->tail;
-
- arc->flag = 1; /* mark arc direction */
- }
-
- /* Loop over subdivision methods */
- for (i = 0; lastBone == NULL && i < SKGEN_SUB_TOTAL; i++)
- {
- switch(G.scene->toolsettings->skgen_subdivisions[i])
- {
- case SKGEN_SUB_LENGTH:
- lastBone = subdivideByLength(arc, head, tail);
- break;
- case SKGEN_SUB_ANGLE:
- lastBone = subdivideByAngle(arc, head, tail);
- break;
- case SKGEN_SUB_CORRELATION:
- lastBone = subdivideByCorrelation(arc, head, tail);
- break;
- }
- }
-
- if (lastBone == NULL)
- {
- EditBone *bone;
- bone = add_editbone("Bone");
- bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
-
- VECCOPY(bone->head, head->p);
- VECCOPY(bone->tail, tail->p);
-
- /* set first and last bone, since there's only one */
- lastBone = bone;
- }
-
- BLI_ghash_insert(arcBoneMap, arc, lastBone);
- }
-
- /* Second pass, setup parent relationship between arcs */
- for (node = rg->nodes.first; node; node = node->next)
- {
- ReebArc *incomingArc = NULL;
- int i;
-
- for (i = 0; i < node->degree; i++)
- {
- arc = (ReebArc*)node->arcs[i];
-
- /* if arc is incoming into the node */
- if ((arc->head == node && arc->flag == -1) || (arc->tail == node && arc->flag == 1))
- {
- if (incomingArc == NULL)
- {
- incomingArc = arc;
- /* loop further to make sure there's only one incoming arc */
- }
- else
- {
- /* skip this node if more than one incomingArc */
- incomingArc = NULL;
- break; /* No need to look further, we are skipping already */
- }
- }
- }
-
- if (incomingArc != NULL)
- {
- EditBone *parentBone = BLI_ghash_lookup(arcBoneMap, incomingArc);
-
- /* Look for outgoing arcs and parent their bones */
- for (i = 0; i < node->degree; i++)
- {
- arc = node->arcs[i];
-
- /* if arc is outgoing from the node */
- if ((arc->head == node && arc->flag == 1) || (arc->tail == node && arc->flag == -1))
- {
- EditBone *childBone = BLI_ghash_lookup(arcBoneMap, arc);
-
- /* find the root bone */
- while(childBone->parent != NULL)
- {
- childBone = childBone->parent;
- }
-
- childBone->parent = parentBone;
- childBone->flag |= BONE_CONNECTED;
- }
- }
- }
- }
-
- BLI_ghash_free(arcBoneMap, NULL, NULL);
-
- BIF_undo_push("Generate Skeleton");
-}
-
-void generateSkeleton(void)
-{
- ReebGraph *reebg;
-
- setcursor_space(SPACE_VIEW3D, CURSOR_WAIT);
-
- reebg = BIF_ReebGraphFromEditMesh();
-
- generateSkeletonFromReebGraph(reebg);
-
- REEB_freeGraph(reebg);
-
- setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
-}