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:
authorChris Want <cwant@ualberta.ca>2003-04-24 04:48:43 +0400
committerChris Want <cwant@ualberta.ca>2003-04-24 04:48:43 +0400
commitc95692df7ca0b2d4746e2e7a597b69a6f30c1676 (patch)
tree413150ab3b6d1b3f82e1a41ea1a78b171edd4330
parent788fa67bdf4a17c2128f15bc1f2fde7d58dd54bb (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).
-rw-r--r--source/blender/blenkernel/BKE_armature.h1
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h1
-rw-r--r--source/blender/blenkernel/intern/armature.c3
-rw-r--r--source/blender/blenkernel/intern/subsurf.c41
-rw-r--r--source/blender/include/BIF_editarmature.h2
-rw-r--r--source/blender/include/BIF_editdeform.h12
-rw-r--r--source/blender/makesdna/DNA_armature_types.h23
-rw-r--r--source/blender/src/editarmature.c363
-rw-r--r--source/blender/src/editdeform.c304
-rw-r--r--source/blender/src/editobject.c9
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);