diff options
author | Chris Want <cwant@ualberta.ca> | 2003-04-24 04:48:43 +0400 |
---|---|---|
committer | Chris Want <cwant@ualberta.ca> | 2003-04-24 04:48:43 +0400 |
commit | c95692df7ca0b2d4746e2e7a597b69a6f30c1676 (patch) | |
tree | 413150ab3b6d1b3f82e1a41ea1a78b171edd4330 /source/blender | |
parent | 788fa67bdf4a17c2128f15bc1f2fde7d58dd54bb (diff) |
Support for auto-skinning when parenting a mesh to an armature.
Applies to bones that do not have a boneclass of unskinnable
(set per bone in editmode in the button window).
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_armature.h | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_subsurf.h | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/armature.c | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/subsurf.c | 41 | ||||
-rw-r--r-- | source/blender/include/BIF_editarmature.h | 2 | ||||
-rw-r--r-- | source/blender/include/BIF_editdeform.h | 12 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_armature_types.h | 23 | ||||
-rw-r--r-- | source/blender/src/editarmature.c | 363 | ||||
-rw-r--r-- | source/blender/src/editdeform.c | 304 | ||||
-rw-r--r-- | source/blender/src/editobject.c | 9 |
10 files changed, 746 insertions, 13 deletions
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 7fabacd48ee..1f9725a4f41 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -77,6 +77,7 @@ struct Bone *get_named_bone (struct bArmature *arm, const char *name); struct Bone *get_indexed_bone (struct bArmature *arm, int index); void make_displists_by_armature (struct Object *ob); void calc_bone_deform (struct Bone *bone, float weight, float *vec, float *co, float *contrib); +float dist_to_bone (float vec[3], float b1[3], float b2[3]); void where_is_armature_time (struct Object *ob, float ctime); void where_is_armature (struct Object *ob); diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h index 2ce3a8b66ed..8025c89dc0e 100644 --- a/source/blender/blenkernel/BKE_subsurf.h +++ b/source/blender/blenkernel/BKE_subsurf.h @@ -39,6 +39,7 @@ void subsurf_to_mesh(struct Object *oldob, struct Mesh *newme); void subsurf_make_mesh(struct Object *ob, short subdiv); void subsurf_make_editmesh(struct Object *ob); struct DispList* subsurf_mesh_to_displist(struct Mesh *me, struct DispList *dl, short subdiv); +void subsurf_calculate_limit_positions(Mesh *me, float (*positions_r)[3]); #endif diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index b4ef397b64b..5fb87e58ecc 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -73,7 +73,6 @@ /* Function prototypes */ static void apply_pose_bonechildren (Bone* bone, bPose* pose, int doit); -static float dist_to_bone (float vec[3], float b1[3], float b2[3]); static Bone *get_named_bone_bonechildren (Bone *bone, const char *name); static Bone *get_indexed_bone_bonechildren (Bone *bone, int *index); /*void make_bone_parent_matrix (Bone* bone);*/ @@ -568,7 +567,7 @@ static int verify_boneptr_children (Bone *cBone, Bone *tBone) } -static float dist_to_bone (float vec[3], float b1[3], float b2[3]) +float dist_to_bone (float vec[3], float b1[3], float b2[3]) { /* float dist=0; */ float bdelta[3]; diff --git a/source/blender/blenkernel/intern/subsurf.c b/source/blender/blenkernel/intern/subsurf.c index 064db5368ea..dd7bfc3dafd 100644 --- a/source/blender/blenkernel/intern/subsurf.c +++ b/source/blender/blenkernel/intern/subsurf.c @@ -901,3 +901,44 @@ DispList* subsurf_mesh_to_displist(Mesh *me, DispList *dl, short subdiv) return subsurf_subdivide_to_displist(hme, subdiv); } + +void subsurf_calculate_limit_positions(Mesh *me, float (*positions_r)[3]) +{ + /* Finds the subsurf limit positions for the verts in a mesh + * and puts them in an array of floats. Please note that the + * calculated vert positions is incorrect for the verts + * on the boundary of the mesh. + */ + HyperMesh *hme= hypermesh_from_mesh(me, NULL); + HyperMesh *nme= hypermesh_new(); + float edge_sum[3], face_sum[3]; + HyperVert *hv; + LinkNode *l; + int i; + + hypermesh_subdivide(hme, nme); + + for (i= me->totvert-1,hv=hme->verts; i>=0; i--,hv=hv->next) { + int N= 0; + + edge_sum[0]= edge_sum[1]= edge_sum[2]= 0.0; + face_sum[0]= face_sum[1]= face_sum[2]= 0.0; + + for (N=0,l=hv->edges; l; N++,l= l->next) { + Vec3Add(edge_sum, ((HyperEdge*) l->link)->ep->co); + } + for (l=hv->faces; l; l= l->next) { + Vec3Add(face_sum, ((HyperFace*) l->link)->mid->co); + } + + positions_r[i][0] = + (hv->nmv->co[0]*N*N + edge_sum[0]*4 + face_sum[0])/(N*(N+5)); + positions_r[i][1] = + (hv->nmv->co[1]*N*N + edge_sum[1]*4 + face_sum[1])/(N*(N+5)); + positions_r[i][2] = + (hv->nmv->co[2]*N*N + edge_sum[2]*4 + face_sum[2])/(N*(N+5)); + } + + hypermesh_free(nme); + hypermesh_free(hme); +} diff --git a/source/blender/include/BIF_editarmature.h b/source/blender/include/BIF_editarmature.h index fac2eae6bf0..f33349c61e6 100644 --- a/source/blender/include/BIF_editarmature.h +++ b/source/blender/include/BIF_editarmature.h @@ -73,6 +73,7 @@ typedef struct EditBone float rot[3], drot[3]; float quat[4], dquat[4]; float obmat[4][4]; + short boneclass; } EditBone; @@ -106,6 +107,7 @@ void selectconnected_posearmature(void); void select_bone_by_name (struct bArmature *arm, char *name, int select); struct Bone *get_first_selected_bone (void); void auto_align_armature(void); +void create_vgroups_from_armature(Object *ob, Object *par); #define BONESEL_TIP 0x08000000 #define BONESEL_ROOT 0x04000000 diff --git a/source/blender/include/BIF_editdeform.h b/source/blender/include/BIF_editdeform.h index 5fcd0473ce5..94c369bc0c4 100644 --- a/source/blender/include/BIF_editdeform.h +++ b/source/blender/include/BIF_editdeform.h @@ -33,12 +33,18 @@ #ifndef BIF_DEFORM_H #define BIF_DEFORM_H +#define WEIGHT_REPLACE 1 +#define WEIGHT_ADD 2 +#define WEIGHT_SUBTRACT 3 + struct Object; struct MDeformVert; struct MDeformWeight; struct bDeformGroup; +struct bDeformGroup *get_named_vertexgroup (Object *ob, char *name); void unique_vertexgroup_name (struct bDeformGroup *dg, struct Object *ob); +struct bDeformGroup *add_defgroup_name (struct Object *ob, char *name); void add_defgroup (struct Object *ob); void del_defgroup (struct Object *ob); void assign_verts_defgroup (void); @@ -46,6 +52,12 @@ void remove_verts_defgroup (int allverts); void sel_verts_defgroup (int select); struct MDeformWeight *verify_defweight (struct MDeformVert *dv, int defgroup); void verify_defgroups (struct Object *ob); +int get_defgroup_num (struct Object *ob, struct bDeformGroup *dg); +void add_vert_to_defgroup (struct Object *ob, struct bDeformGroup *dg, + int vertnum, float weight, + int assignmode); +void remove_vert_defgroup (struct Object *ob, struct bDeformGroup *dg, + int vertnum); #endif diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h index 95dc6d8689e..867f62ff039 100644 --- a/source/blender/makesdna/DNA_armature_types.h +++ b/source/blender/makesdna/DNA_armature_types.h @@ -61,6 +61,10 @@ typedef struct Bone { float defmat[4][4]; float irestmat[4][4]; /* Cached inverse of rest matrix (objectspace)*/ float posemat[4][4]; /* Cached pose matrix (objectspace)*/ + short boneclass; + short filler1; + short filler2; + short filler3; }Bone; typedef struct bArmature { @@ -119,5 +123,22 @@ enum { BONE_ISMUSCLEBIT }; -#endif +enum { + BONE_SKINNABLE = 0, + BONE_UNSKINNABLE, + BONE_HEAD, + BONE_NECK, + BONE_BACK, + BONE_SHOULDER, + BONE_ARM, + BONE_HAND, + BONE_FINGER, + BONE_THUMB, + BONE_PELVIS, + BONE_LEG, + BONE_FOOT, + BONE_TOE, + BONE_TENTACLE +}; +#endif diff --git a/source/blender/src/editarmature.c b/source/blender/src/editarmature.c index 6e2fbde6fe7..fdff0ec08f8 100644 --- a/source/blender/src/editarmature.c +++ b/source/blender/src/editarmature.c @@ -58,6 +58,7 @@ #include "DNA_screen_types.h" #include "DNA_space_types.h" #include "DNA_view3d_types.h" +#include "DNA_mesh_types.h" #include "BKE_utildefines.h" #include "BKE_action.h" @@ -65,6 +66,7 @@ #include "BKE_constraint.h" #include "BKE_global.h" #include "BKE_object.h" +#include "BKE_subsurf.h" #include "BIF_gl.h" #include "BIF_graphics.h" @@ -76,6 +78,7 @@ #include "BIF_editarmature.h" #include "BIF_poseobject.h" #include "BIF_mywindow.h" +#include "BIF_editdeform.h" #include "BDR_editobject.h" #include "BDR_drawobject.h" @@ -810,6 +813,8 @@ static void editbones_to_armature (ListBase *list, Object *ob) newBone->weight = eBone->weight; newBone->dist = eBone->dist; + newBone->boneclass = eBone->boneclass; + memcpy (newBone->loc, eBone->loc, sizeof(eBone->loc)); memcpy (newBone->dloc, eBone->dloc, sizeof(eBone->dloc)); /* memcpy (newBone->orig, eBone->orig, sizeof(eBone->orig));*/ @@ -906,6 +911,8 @@ void load_editArmature(void) newBone->weight = eBone->weight; newBone->dist = eBone->dist; + newBone->boneclass = eBone->boneclass; + memcpy (newBone->loc, eBone->loc, sizeof(eBone->loc)); memcpy (newBone->dloc, eBone->dloc, sizeof(eBone->dloc)); /* memcpy (newBone->orig, eBone->orig, sizeof(eBone->orig));*/ @@ -1081,6 +1088,7 @@ static void make_boneList(ListBase* list, ListBase *bones, EditBone *parent) #endif eBone->dist= curBone->dist; eBone->weight= curBone->weight; + eBone->boneclass = curBone->boneclass; memcpy (eBone->loc, curBone->loc, sizeof(curBone->loc)); memcpy (eBone->dloc, curBone->dloc, sizeof(curBone->dloc)); /* memcpy (eBone->orig, curBone->orig, sizeof(curBone->orig));*/ @@ -1587,6 +1595,7 @@ static void add_bone_input (Object *ob) bone->weight= 1.0F; bone->dist= 1.0F; + bone->boneclass = BONE_SKINNABLE; /* Project cursor center to screenspace. */ getmouseco_areawin(mval); @@ -1781,8 +1790,35 @@ void armaturebuts(void) /* Dist and weight buttons */ uiBlockSetCol(block, BUTGREY); - uiDefButF(block, NUM,REDRAWVIEW3D, "Dist:", bx+320, by, 110, 18, &curBone->dist, 0.0, 1000.0, 10.0, 0.0, "Bone deformation distance"); - uiDefButF(block, NUM,REDRAWVIEW3D, "Weight:", bx+438, by, 110, 18, &curBone->weight, 0.0F, 1000.0F, 10.0F, 0.0F, "Bone deformation weight"); + but=uiDefButI(block, MENU, REDRAWVIEW3D, + "Skinnable %x0|" + "Unskinnable %x1|" + "Head %x2|" + "Neck %x3|" + "Back %x4|" + "Shoulder %x5|" + "Arm %x6|" + "Hand %x7|" + "Finger %x8|" + "Thumb %x9|" + "Pelvis %x10|" + "Leg %x11|" + "Foot %x12|" + "Toe %x13|" + "Tentacle %x14", + bx+320,by,97,18, + &curBone->boneclass, + 0.0, 0.0, 0.0, 0.0, + "Classification of armature element"); + + /* Dist and weight buttons */ + uiBlockSetCol(block, BUTGREY); + uiDefButF(block, NUM,REDRAWVIEW3D, "Dist:", bx+425, by, + 110, 18, &curBone->dist, 0.0, 1000.0, 10.0, 0.0, + "Bone deformation distance"); + uiDefButF(block, NUM,REDRAWVIEW3D, "Weight:", bx+543, by, + 110, 18, &curBone->weight, 0.0F, 1000.0F, + 10.0F, 0.0F, "Bone deformation weight"); by-=19; } @@ -2108,6 +2144,8 @@ void extrude_armature(void) newbone->flag |= BONE_QUATROT; newbone->weight= curbone->weight; newbone->dist= curbone->dist; + newbone->boneclass= curbone->boneclass; + Mat4One(newbone->obmat); /* See if there are any ik children of the parent */ @@ -2586,3 +2624,324 @@ void auto_align_armature(void) } } +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; +} + +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. Is such a vertex group aleady exist + * the routine exits. + */ + if (!get_named_vertexgroup(ob,bone->name)) { + add_defgroup_name(ob, bone->name); + return 1; + } + return 0; +} + +int bone_skinnable(Object *ob, Bone *bone, void *data) +{ + /* Bones that are not of boneclass BONE_UNSKINNABLE + * 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; + + if ( bone->boneclass != BONE_UNSKINNABLE ) { + if (data != NULL) { + hbone = (Bone ***) data; + **hbone = bone; + ++*hbone; + } + return 1; + } + return 0; +} + +int dgroup_skinnable(Object *ob, Bone *bone, void *data) { + /* Bones that are not of boneclass BONE_UNSKINNABLE + * 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; + + if ( bone->boneclass != BONE_UNSKINNABLE ) { + if ( !(defgroup = get_named_vertexgroup(ob, bone->name)) ) { + defgroup = add_defgroup_name(ob, bone->name); + } + + if (data != NULL) { + hgroup = (bDeformGroup ***) data; + **hgroup = defgroup; + ++*hgroup; + } + return 1; + } + return 0; +} + +void add_verts_to_closest_dgroup(Object *ob, Object *par) +{ + /* This function implements a crude form of + * auto-skinning: vertices are assigned to the + * deformation groups associated with bones based + * on thier proximity to a bone. Every vert is + * given a weight of 1.0 to the weight group + * cooresponding to the bone that it is + * closest to. The vertex may also be assigned to + * a deformation group associated to a bone + * that is within 10% of the mninimum distance + * between the bone and the nearest vert -- the + * cooresponding weight will fall-off to zero + * as the distance approaches the 10% tolerance mark. + * If the mesh has subsurf enabled then the verts + * on the subsurf limit surface is used to generate + * the weights rather than the verts on the cage + * mesh. + */ + + bArmature *arm; + Bone **bonelist, **bonehandle, *bone; + bDeformGroup **dgrouplist, **dgrouphandle, *defgroup; + float *distance, mindist = 0.0, weight = 0.0; + float root[3]; + float tip[3]; + float real_co[3]; + float *subverts = NULL; + float *subvert; + Mesh *mesh; + MVert *vert; + + int numbones, i, j; + + /* If the parent object is not an armature exit */ + arm = get_armature(par); + if (!arm) + return; + + /* count the number of skinnable bones */ + numbones = bone_looper(ob, arm->bonebase.first, NULL, + bone_skinnable); + + /* create an array of pointer to bones that are skinnable + * and fill it with all of the skinnable bones + */ + bonelist = MEM_mallocN(numbones*sizeof(Bone *), "bonelist"); + bonehandle = bonelist; + bone_looper(ob, arm->bonebase.first, &bonehandle, + bone_skinnable); + + /* create an array of pointers to the deform groups that + * coorespond to the skinnable bones (creating them + * as necessary. + */ + dgrouplist = MEM_mallocN(numbones*sizeof(bDeformGroup *), "dgrouplist"); + dgrouphandle = dgrouplist; + bone_looper(ob, arm->bonebase.first, &dgrouphandle, + dgroup_skinnable); + + /* create an array of floats that will be used for each vert + * to hold the distance to each bone. + */ + distance = MEM_mallocN(numbones*sizeof(float), "distance"); + + mesh = (Mesh*)ob->data; + + /* Is subsurf on? Lets use the verts on the limit surface then */ + if ( (mesh->flag&ME_SUBSURF) && (mesh->subdiv > 0) ) { + subverts = MEM_mallocN(3*mesh->totvert*sizeof(float), "subverts"); + subsurf_calculate_limit_positions(mesh, subverts); + } + + /* for each vertex in the mesh ... + */ + for ( i=0 ; i < mesh->totvert ; ++i ) { + /* get the vert in global coords + */ + + if (subverts) { + subvert = subverts + i*3; + VECCOPY (real_co, subvert); + } + else { + vert = mesh->mvert + i; + VECCOPY (real_co, vert->co); + } + Mat4MulVecfl(ob->obmat, real_co); + + + /* for each skinnable bone ... + */ + for (j=0; j < numbones; ++j) { + bone = bonelist[j]; + + /* get the root of the bone in global coords + */ + get_bone_root_pos (bone, root, 0); + Mat4MulVecfl(par->obmat, root); + + /* get the tip of the bone in global coords + */ + get_bone_tip_pos (bone, tip, 0); + Mat4MulVecfl(par->obmat, tip); + + /* store the distance from the bone to + * the vert + */ + distance[j] = dist_to_bone(real_co, root, tip); + + /* if this is the first bone, or if this + * bone is less than mindist, then set this + * distance to mindist + */ + if (j == 0) { + mindist = distance[j]; + } + else if (distance[j] < mindist) { + mindist = distance[j]; + } + } + + /* for each deform group ... + */ + for (j=0; j < numbones; ++j) { + defgroup = dgrouplist[j]; + + /* if the cooresponding bone is the closest one + * add the vert to the deform group with weight 1 + */ + if (distance[j] <= mindist) { + add_vert_to_defgroup (ob, defgroup, i, 1.0, WEIGHT_REPLACE); + } + + /* if the cooresponding bone is within 10% of the + * nearest distance, add the vert to the + * deform group with a weight that declines with + * distance + */ + else if (distance[j] <= mindist*1.10) { + if (mindist > 0) + weight = 1.0 - (distance[j] - mindist) / (mindist * 0.10); + add_vert_to_defgroup (ob, defgroup, i, weight, WEIGHT_REPLACE); + } + + /* if the cooresponding bone is outside of the 10% tolerance + * then remove the vert from the weight group (if it is + * in that group) + */ + else { + remove_vert_defgroup (ob, defgroup, i); + } + } + } + + /* free the memory allocated + */ + MEM_freeN(bonelist); + MEM_freeN(dgrouplist); + MEM_freeN(distance); + if (subverts) MEM_freeN(subverts); +} + +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("Vertex Groups from Bones? %t|No Thanks %x1|Empty %x2|" + "Closest Bone %x3"); + 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); + break; + + case 3: + /* Traverse the bone list, trying to create vertex groups + * that are populated with the vertices for which the + * bone is closest. + */ + add_verts_to_closest_dgroup(ob, par); + break; + + } +} diff --git a/source/blender/src/editdeform.c b/source/blender/src/editdeform.c index c4aa8d4b4cc..bc37ac9a07c 100644 --- a/source/blender/src/editdeform.c +++ b/source/blender/src/editdeform.c @@ -114,20 +114,32 @@ the specified defweight group */ return dv->dw+(dv->totweight-1); } -void add_defgroup (Object *ob) +void add_defgroup (Object *ob) { + add_defgroup_name (ob, "Group"); +} + +bDeformGroup *add_defgroup_name (Object *ob, char *name) { bDeformGroup *defgroup; - + if (!ob) - return; - + return NULL; + defgroup = MEM_callocN (sizeof(bDeformGroup), "deformGroup"); - strcpy (defgroup->name, "Group"); + + /* I think there should be some length + * checking here -- don't know why NaN + * never checks name lengths (see + * unique_vertexgroup_name, for example). + */ + strcpy (defgroup->name, name); BLI_addtail(&ob->defbase, defgroup); unique_vertexgroup_name(defgroup, ob); ob->actdef = BLI_countlist(&ob->defbase); + + return defgroup; } void del_defgroup (Object *ob) @@ -166,6 +178,233 @@ void del_defgroup (Object *ob) BLI_freelinkN (&ob->defbase, defgroup); } +void create_dverts(Mesh *me) +{ + /* create deform verts for the mesh + */ + int i; + + me->dvert= MEM_mallocN(sizeof(MDeformVert)*me->totvert, "deformVert"); + for (i=0; i < me->totvert; ++i) { + me->dvert[i].totweight = 0; + me->dvert[i].dw = NULL; + } +} + +int get_defgroup_num (Object *ob, bDeformGroup *dg) +{ + /* Fetch the location of this deform group + * within the linked list of deform groups. + * (this number is stored in the deform + * weights of the deform verts to link them + * to this deform group) deform deform + * deform blah blah deform + */ + + bDeformGroup *eg; + int def_nr; + + eg = ob->defbase.first; + def_nr = 0; + + /* loop through all deform groups + */ + while (eg != NULL){ + + /* if the current deform group is + * the one we are after, return + * def_nr + */ + if (eg == dg){ + break; + } + ++def_nr; + eg = eg->next; + } + + /* if there was no deform group found then + * return -1 (should set up a nice symbolic + * constant for this) + */ + if (eg == NULL) return -1; + + return def_nr; + +} + + +void remove_vert_def_nr (Object *ob, int def_nr, int vertnum) +{ + /* This routine removes the vertex from the deform + * group with number def_nr. + * + * This routine is meant to be fast, so it is the + * responsibility of the calling routine to: + * a) test whether ob is non-NULL + * b) test whether ob is a mesh + * c) calculate def_nr + */ + + MDeformWeight *newdw; + MDeformVert *dvert; + int i; + + /* if this mesh has no deform mesh abort + */ + if (!((Mesh*)ob->data)->dvert) return; + + /* get the deform mesh cooresponding to the + * vertnum + */ + dvert = ((Mesh*)ob->data)->dvert + vertnum; + + /* for all of the deform weights in the + * deform vert + */ + for (i=dvert->totweight - 1 ; i>=0 ; i--){ + + /* if the def_nr is the same as the one + * for our weight group then remove it + * from this deform vert. + */ + if (dvert->dw[i].def_nr == def_nr) { + dvert->totweight--; + + /* if there are still other deform weights + * attached to this vert then remove this + * deform weight, and reshuffle the others + */ + if (dvert->totweight) { + newdw = MEM_mallocN (sizeof(MDeformWeight)*(dvert->totweight), + "deformWeight"); + if (dvert->dw){ + memcpy (newdw, dvert->dw, sizeof(MDeformWeight)*i); + memcpy (newdw+i, dvert->dw+i+1, + sizeof(MDeformWeight)*(dvert->totweight-i)); + MEM_freeN (dvert->dw); + } + dvert->dw=newdw; + } + /* if there are no other deform weights + * left then just remove the deform weight + */ + else { + MEM_freeN (dvert->dw); + dvert->dw = NULL; + } + } + } + +} + +void add_vert_defnr (Object *ob, int def_nr, int vertnum, + float weight, int assignmode) +{ + /* add the vert to the deform group with the + * specified number + */ + + MDeformVert *dv; + MDeformWeight *newdw; + int i; + + /* get the vert + */ + dv = ((Mesh*)ob->data)->dvert + vertnum; + + /* Lets first check to see if this vert is + * already in the weight group -- if so + * lets update it + */ + for (i=0; i<dv->totweight; i++){ + + /* if this weight cooresponds to the + * deform group, then add it using + * the assign mode provided + */ + if (dv->dw[i].def_nr == def_nr){ + + switch (assignmode) { + case WEIGHT_REPLACE: + dv->dw[i].weight=weight; + break; + case WEIGHT_ADD: + dv->dw[i].weight+=weight; + if (dv->dw[i].weight >= 1.0) + dv->dw[i].weight = 1.0; + break; + case WEIGHT_SUBTRACT: + dv->dw[i].weight-=weight; + /* if the weight is zero or less then + * remove the vert from the deform group + */ + if (dv->dw[i].weight <= 0.0) + remove_vert_def_nr(ob, def_nr, vertnum); + break; + } + return; + } + } + + /* if the vert wasn't in the deform group then + * we must take a different form of action ... + */ + + switch (assignmode) { + case WEIGHT_SUBTRACT: + /* if we are subtracting then we don't + * need to do anything + */ + return; + + case WEIGHT_REPLACE: + case WEIGHT_ADD: + /* if we are doing an additive assignment, then + * we need to create the deform weight + */ + newdw = MEM_callocN (sizeof(MDeformWeight)*(dv->totweight+1), + "deformWeight"); + if (dv->dw){ + memcpy (newdw, dv->dw, sizeof(MDeformWeight)*dv->totweight); + MEM_freeN (dv->dw); + } + dv->dw=newdw; + + dv->dw[dv->totweight].weight=weight; + dv->dw[dv->totweight].def_nr=def_nr; + + dv->totweight++; + break; + } +} + +void add_vert_to_defgroup (Object *ob, bDeformGroup *dg, int vertnum, + float weight, int assignmode) +{ + /* add the vert to the deform group with the + * specified assign mode + */ + int def_nr; + + /* get the deform group number, exit if + * it can't be found + */ + def_nr = get_defgroup_num(ob, dg); + if (def_nr < 0) return; + + /* if this mesh has no deform verts then + * create some + */ + if (!((Mesh*)ob->data)->dvert) { + create_dverts((Mesh*)ob->data); + } + + /* call another function to do the work + */ + add_vert_defnr (ob, def_nr, vertnum, weight, assignmode); +} + + void assign_verts_defgroup (void) /* Only available in editmode */ { @@ -230,6 +469,35 @@ void assign_verts_defgroup (void) } +void remove_vert_defgroup (Object *ob, bDeformGroup *dg, int vertnum) +{ + /* This routine removes the vertex from the specified + * deform group. + */ + + int def_nr; + + /* if the object is NULL abort + */ + if (!ob) + return; + + /* if this isn't a mesh abort + */ + if (ob->type != OB_MESH) return; + + /* get the deform number that cooresponds + * to this deform group, and abort if it + * can not be found. + */ + def_nr = get_defgroup_num(ob, dg); + if (def_nr < 0) return; + + /* call another routine to do the work + */ + remove_vert_def_nr (ob, def_nr, vertnum); +} + void remove_verts_defgroup (int allverts) /* Only available in editmode */ { @@ -286,12 +554,18 @@ void remove_verts_defgroup (int allverts) void verify_defgroups (Object *ob) { - /* Ensure the defbase & the dverts match */ + /* Ensure the defbase & the dverts match */ switch (ob->type){ case OB_MESH: + + /* I'm pretty sure this means "If there are no + * deform groups defined, yet there are deform + * vertices, then delete the deform vertices + */ if (!ob->defbase.first){ if (((Mesh*)ob->data)->dvert){ - free_dverts(((Mesh*)ob->data)->dvert, ((Mesh*)ob->data)->totvert); + free_dverts(((Mesh*)ob->data)->dvert, + ((Mesh*)ob->data)->totvert); ((Mesh*)ob->data)->dvert=NULL; } } @@ -301,6 +575,22 @@ void verify_defgroups (Object *ob) } } +bDeformGroup *get_named_vertexgroup(Object *ob, char *name) +{ + /* return a pointer to the deform group with this name + * or return NULL otherwise. + */ + bDeformGroup *curdef; + + for (curdef = ob->defbase.first; curdef; curdef=curdef->next){ + if (!strcmp(curdef->name, name)){ + return curdef; + } + } + return NULL; +} + + void unique_vertexgroup_name (bDeformGroup *dg, Object *ob) { char tempname[64]; diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c index ba5db29bd10..ec3386c511b 100644 --- a/source/blender/src/editobject.c +++ b/source/blender/src/editobject.c @@ -850,7 +850,14 @@ void make_parent(void) memset(base->object->loc, 0, 3*sizeof(float)); } else { - if(mode==PARSKEL && par->type == OB_ARMATURE) { + if(mode==PARSKEL && par->type == OB_ARMATURE) { + /* Prompt the user as to whether he wants to + * add some vertex groups based on the bones + * in the parent armature. + */ + create_vgroups_from_armature(base->object, + par); + base->object->partype= PAROBJECT; what_does_parent(base->object); Mat4One (base->object->parentinv); |