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).
This commit is contained in:
@@ -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);
|
struct Bone *get_indexed_bone (struct bArmature *arm, int index);
|
||||||
void make_displists_by_armature (struct Object *ob);
|
void make_displists_by_armature (struct Object *ob);
|
||||||
void calc_bone_deform (struct Bone *bone, float weight, float *vec, float *co, float *contrib);
|
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_time (struct Object *ob, float ctime);
|
||||||
void where_is_armature (struct Object *ob);
|
void where_is_armature (struct Object *ob);
|
||||||
|
@@ -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_mesh(struct Object *ob, short subdiv);
|
||||||
void subsurf_make_editmesh(struct Object *ob);
|
void subsurf_make_editmesh(struct Object *ob);
|
||||||
struct DispList* subsurf_mesh_to_displist(struct Mesh *me, struct DispList *dl, short subdiv);
|
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
|
#endif
|
||||||
|
|
||||||
|
@@ -73,7 +73,6 @@
|
|||||||
/* Function prototypes */
|
/* Function prototypes */
|
||||||
|
|
||||||
static void apply_pose_bonechildren (Bone* bone, bPose* pose, int doit);
|
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_named_bone_bonechildren (Bone *bone, const char *name);
|
||||||
static Bone *get_indexed_bone_bonechildren (Bone *bone, int *index);
|
static Bone *get_indexed_bone_bonechildren (Bone *bone, int *index);
|
||||||
/*void make_bone_parent_matrix (Bone* bone);*/
|
/*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 dist=0; */
|
||||||
float bdelta[3];
|
float bdelta[3];
|
||||||
|
@@ -901,3 +901,44 @@ DispList* subsurf_mesh_to_displist(Mesh *me, DispList *dl, short subdiv)
|
|||||||
|
|
||||||
return subsurf_subdivide_to_displist(hme, 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);
|
||||||
|
}
|
||||||
|
@@ -73,6 +73,7 @@ typedef struct EditBone
|
|||||||
float rot[3], drot[3];
|
float rot[3], drot[3];
|
||||||
float quat[4], dquat[4];
|
float quat[4], dquat[4];
|
||||||
float obmat[4][4];
|
float obmat[4][4];
|
||||||
|
short boneclass;
|
||||||
|
|
||||||
|
|
||||||
} EditBone;
|
} EditBone;
|
||||||
@@ -106,6 +107,7 @@ void selectconnected_posearmature(void);
|
|||||||
void select_bone_by_name (struct bArmature *arm, char *name, int select);
|
void select_bone_by_name (struct bArmature *arm, char *name, int select);
|
||||||
struct Bone *get_first_selected_bone (void);
|
struct Bone *get_first_selected_bone (void);
|
||||||
void auto_align_armature(void);
|
void auto_align_armature(void);
|
||||||
|
void create_vgroups_from_armature(Object *ob, Object *par);
|
||||||
|
|
||||||
#define BONESEL_TIP 0x08000000
|
#define BONESEL_TIP 0x08000000
|
||||||
#define BONESEL_ROOT 0x04000000
|
#define BONESEL_ROOT 0x04000000
|
||||||
|
@@ -33,12 +33,18 @@
|
|||||||
#ifndef BIF_DEFORM_H
|
#ifndef BIF_DEFORM_H
|
||||||
#define BIF_DEFORM_H
|
#define BIF_DEFORM_H
|
||||||
|
|
||||||
|
#define WEIGHT_REPLACE 1
|
||||||
|
#define WEIGHT_ADD 2
|
||||||
|
#define WEIGHT_SUBTRACT 3
|
||||||
|
|
||||||
struct Object;
|
struct Object;
|
||||||
struct MDeformVert;
|
struct MDeformVert;
|
||||||
struct MDeformWeight;
|
struct MDeformWeight;
|
||||||
struct bDeformGroup;
|
struct bDeformGroup;
|
||||||
|
|
||||||
|
struct bDeformGroup *get_named_vertexgroup (Object *ob, char *name);
|
||||||
void unique_vertexgroup_name (struct bDeformGroup *dg, struct Object *ob);
|
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 add_defgroup (struct Object *ob);
|
||||||
void del_defgroup (struct Object *ob);
|
void del_defgroup (struct Object *ob);
|
||||||
void assign_verts_defgroup (void);
|
void assign_verts_defgroup (void);
|
||||||
@@ -46,6 +52,12 @@ void remove_verts_defgroup (int allverts);
|
|||||||
void sel_verts_defgroup (int select);
|
void sel_verts_defgroup (int select);
|
||||||
struct MDeformWeight *verify_defweight (struct MDeformVert *dv, int defgroup);
|
struct MDeformWeight *verify_defweight (struct MDeformVert *dv, int defgroup);
|
||||||
void verify_defgroups (struct Object *ob);
|
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
|
#endif
|
||||||
|
|
||||||
|
@@ -61,6 +61,10 @@ typedef struct Bone {
|
|||||||
float defmat[4][4];
|
float defmat[4][4];
|
||||||
float irestmat[4][4]; /* Cached inverse of rest matrix (objectspace)*/
|
float irestmat[4][4]; /* Cached inverse of rest matrix (objectspace)*/
|
||||||
float posemat[4][4]; /* Cached pose matrix (objectspace)*/
|
float posemat[4][4]; /* Cached pose matrix (objectspace)*/
|
||||||
|
short boneclass;
|
||||||
|
short filler1;
|
||||||
|
short filler2;
|
||||||
|
short filler3;
|
||||||
}Bone;
|
}Bone;
|
||||||
|
|
||||||
typedef struct bArmature {
|
typedef struct bArmature {
|
||||||
@@ -119,5 +123,22 @@ enum {
|
|||||||
BONE_ISMUSCLEBIT
|
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
|
||||||
|
@@ -58,6 +58,7 @@
|
|||||||
#include "DNA_screen_types.h"
|
#include "DNA_screen_types.h"
|
||||||
#include "DNA_space_types.h"
|
#include "DNA_space_types.h"
|
||||||
#include "DNA_view3d_types.h"
|
#include "DNA_view3d_types.h"
|
||||||
|
#include "DNA_mesh_types.h"
|
||||||
|
|
||||||
#include "BKE_utildefines.h"
|
#include "BKE_utildefines.h"
|
||||||
#include "BKE_action.h"
|
#include "BKE_action.h"
|
||||||
@@ -65,6 +66,7 @@
|
|||||||
#include "BKE_constraint.h"
|
#include "BKE_constraint.h"
|
||||||
#include "BKE_global.h"
|
#include "BKE_global.h"
|
||||||
#include "BKE_object.h"
|
#include "BKE_object.h"
|
||||||
|
#include "BKE_subsurf.h"
|
||||||
|
|
||||||
#include "BIF_gl.h"
|
#include "BIF_gl.h"
|
||||||
#include "BIF_graphics.h"
|
#include "BIF_graphics.h"
|
||||||
@@ -76,6 +78,7 @@
|
|||||||
#include "BIF_editarmature.h"
|
#include "BIF_editarmature.h"
|
||||||
#include "BIF_poseobject.h"
|
#include "BIF_poseobject.h"
|
||||||
#include "BIF_mywindow.h"
|
#include "BIF_mywindow.h"
|
||||||
|
#include "BIF_editdeform.h"
|
||||||
|
|
||||||
#include "BDR_editobject.h"
|
#include "BDR_editobject.h"
|
||||||
#include "BDR_drawobject.h"
|
#include "BDR_drawobject.h"
|
||||||
@@ -810,6 +813,8 @@ static void editbones_to_armature (ListBase *list, Object *ob)
|
|||||||
|
|
||||||
newBone->weight = eBone->weight;
|
newBone->weight = eBone->weight;
|
||||||
newBone->dist = eBone->dist;
|
newBone->dist = eBone->dist;
|
||||||
|
newBone->boneclass = eBone->boneclass;
|
||||||
|
|
||||||
memcpy (newBone->loc, eBone->loc, sizeof(eBone->loc));
|
memcpy (newBone->loc, eBone->loc, sizeof(eBone->loc));
|
||||||
memcpy (newBone->dloc, eBone->dloc, sizeof(eBone->dloc));
|
memcpy (newBone->dloc, eBone->dloc, sizeof(eBone->dloc));
|
||||||
/* memcpy (newBone->orig, eBone->orig, sizeof(eBone->orig));*/
|
/* memcpy (newBone->orig, eBone->orig, sizeof(eBone->orig));*/
|
||||||
@@ -906,6 +911,8 @@ void load_editArmature(void)
|
|||||||
|
|
||||||
newBone->weight = eBone->weight;
|
newBone->weight = eBone->weight;
|
||||||
newBone->dist = eBone->dist;
|
newBone->dist = eBone->dist;
|
||||||
|
newBone->boneclass = eBone->boneclass;
|
||||||
|
|
||||||
memcpy (newBone->loc, eBone->loc, sizeof(eBone->loc));
|
memcpy (newBone->loc, eBone->loc, sizeof(eBone->loc));
|
||||||
memcpy (newBone->dloc, eBone->dloc, sizeof(eBone->dloc));
|
memcpy (newBone->dloc, eBone->dloc, sizeof(eBone->dloc));
|
||||||
/* memcpy (newBone->orig, eBone->orig, sizeof(eBone->orig));*/
|
/* memcpy (newBone->orig, eBone->orig, sizeof(eBone->orig));*/
|
||||||
@@ -1081,6 +1088,7 @@ static void make_boneList(ListBase* list, ListBase *bones, EditBone *parent)
|
|||||||
#endif
|
#endif
|
||||||
eBone->dist= curBone->dist;
|
eBone->dist= curBone->dist;
|
||||||
eBone->weight= curBone->weight;
|
eBone->weight= curBone->weight;
|
||||||
|
eBone->boneclass = curBone->boneclass;
|
||||||
memcpy (eBone->loc, curBone->loc, sizeof(curBone->loc));
|
memcpy (eBone->loc, curBone->loc, sizeof(curBone->loc));
|
||||||
memcpy (eBone->dloc, curBone->dloc, sizeof(curBone->dloc));
|
memcpy (eBone->dloc, curBone->dloc, sizeof(curBone->dloc));
|
||||||
/* memcpy (eBone->orig, curBone->orig, sizeof(curBone->orig));*/
|
/* memcpy (eBone->orig, curBone->orig, sizeof(curBone->orig));*/
|
||||||
@@ -1587,6 +1595,7 @@ static void add_bone_input (Object *ob)
|
|||||||
|
|
||||||
bone->weight= 1.0F;
|
bone->weight= 1.0F;
|
||||||
bone->dist= 1.0F;
|
bone->dist= 1.0F;
|
||||||
|
bone->boneclass = BONE_SKINNABLE;
|
||||||
|
|
||||||
/* Project cursor center to screenspace. */
|
/* Project cursor center to screenspace. */
|
||||||
getmouseco_areawin(mval);
|
getmouseco_areawin(mval);
|
||||||
@@ -1781,8 +1790,35 @@ void armaturebuts(void)
|
|||||||
|
|
||||||
/* Dist and weight buttons */
|
/* Dist and weight buttons */
|
||||||
uiBlockSetCol(block, BUTGREY);
|
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");
|
but=uiDefButI(block, MENU, REDRAWVIEW3D,
|
||||||
uiDefButF(block, NUM,REDRAWVIEW3D, "Weight:", bx+438, by, 110, 18, &curBone->weight, 0.0F, 1000.0F, 10.0F, 0.0F, "Bone deformation weight");
|
"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;
|
by-=19;
|
||||||
}
|
}
|
||||||
@@ -2108,6 +2144,8 @@ void extrude_armature(void)
|
|||||||
newbone->flag |= BONE_QUATROT;
|
newbone->flag |= BONE_QUATROT;
|
||||||
newbone->weight= curbone->weight;
|
newbone->weight= curbone->weight;
|
||||||
newbone->dist= curbone->dist;
|
newbone->dist= curbone->dist;
|
||||||
|
newbone->boneclass= curbone->boneclass;
|
||||||
|
|
||||||
Mat4One(newbone->obmat);
|
Mat4One(newbone->obmat);
|
||||||
|
|
||||||
/* See if there are any ik children of the parent */
|
/* 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -114,20 +114,32 @@ the specified defweight group */
|
|||||||
return dv->dw+(dv->totweight-1);
|
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;
|
bDeformGroup *defgroup;
|
||||||
|
|
||||||
if (!ob)
|
if (!ob)
|
||||||
return;
|
return NULL;
|
||||||
|
|
||||||
defgroup = MEM_callocN (sizeof(bDeformGroup), "deformGroup");
|
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);
|
BLI_addtail(&ob->defbase, defgroup);
|
||||||
unique_vertexgroup_name(defgroup, ob);
|
unique_vertexgroup_name(defgroup, ob);
|
||||||
|
|
||||||
ob->actdef = BLI_countlist(&ob->defbase);
|
ob->actdef = BLI_countlist(&ob->defbase);
|
||||||
|
|
||||||
|
return defgroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
void del_defgroup (Object *ob)
|
void del_defgroup (Object *ob)
|
||||||
@@ -166,6 +178,233 @@ void del_defgroup (Object *ob)
|
|||||||
BLI_freelinkN (&ob->defbase, defgroup);
|
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)
|
void assign_verts_defgroup (void)
|
||||||
/* Only available in editmode */
|
/* 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)
|
void remove_verts_defgroup (int allverts)
|
||||||
/* Only available in editmode */
|
/* Only available in editmode */
|
||||||
{
|
{
|
||||||
@@ -286,12 +554,18 @@ void remove_verts_defgroup (int allverts)
|
|||||||
|
|
||||||
void verify_defgroups (Object *ob)
|
void verify_defgroups (Object *ob)
|
||||||
{
|
{
|
||||||
/* Ensure the defbase & the dverts match */
|
/* Ensure the defbase & the dverts match */
|
||||||
switch (ob->type){
|
switch (ob->type){
|
||||||
case OB_MESH:
|
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 (!ob->defbase.first){
|
||||||
if (((Mesh*)ob->data)->dvert){
|
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;
|
((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)
|
void unique_vertexgroup_name (bDeformGroup *dg, Object *ob)
|
||||||
{
|
{
|
||||||
char tempname[64];
|
char tempname[64];
|
||||||
|
@@ -850,7 +850,14 @@ void make_parent(void)
|
|||||||
memset(base->object->loc, 0, 3*sizeof(float));
|
memset(base->object->loc, 0, 3*sizeof(float));
|
||||||
}
|
}
|
||||||
else {
|
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;
|
base->object->partype= PAROBJECT;
|
||||||
what_does_parent(base->object);
|
what_does_parent(base->object);
|
||||||
Mat4One (base->object->parentinv);
|
Mat4One (base->object->parentinv);
|
||||||
|
Reference in New Issue
Block a user