diff '--exclude=.svn' -rupN /home/kesten/VCP/Bazaar/blender/blender-svn/blender/source/blender/editors/object/object_intern.h /home/kesten/VCP/Bazaar/blender/features-branch/blender/source/blender/editors/object/object_intern.h --- /home/kesten/VCP/Bazaar/blender/blender-svn/blender/source/blender/editors/object/object_intern.h 2012-06-21 00:17:29.736447250 -0500 +++ /home/kesten/VCP/Bazaar/blender/features-branch/blender/source/blender/editors/object/object_intern.h 2012-06-24 16:37:07.940120237 -0500 @@ -211,6 +211,7 @@ void OBJECT_OT_vertex_group_fix(struct w void OBJECT_OT_vertex_group_invert(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_blend(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_clean(struct wmOperatorType *ot); +void OBJECT_OT_vertex_group_cull_num_weights(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_mirror(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_set_active(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_sort(struct wmOperatorType *ot); diff '--exclude=.svn' -rupN /home/kesten/VCP/Bazaar/blender/blender-svn/blender/source/blender/editors/object/object_ops.c /home/kesten/VCP/Bazaar/blender/features-branch/blender/source/blender/editors/object/object_ops.c --- /home/kesten/VCP/Bazaar/blender/blender-svn/blender/source/blender/editors/object/object_ops.c 2012-06-21 00:17:29.736447250 -0500 +++ /home/kesten/VCP/Bazaar/blender/features-branch/blender/source/blender/editors/object/object_ops.c 2012-06-24 16:37:07.940120237 -0500 @@ -186,6 +186,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_vertex_group_levels); WM_operatortype_append(OBJECT_OT_vertex_group_blend); WM_operatortype_append(OBJECT_OT_vertex_group_clean); + WM_operatortype_append(OBJECT_OT_vertex_group_cull_num_weights); WM_operatortype_append(OBJECT_OT_vertex_group_mirror); WM_operatortype_append(OBJECT_OT_vertex_group_set_active); WM_operatortype_append(OBJECT_OT_vertex_group_sort); diff '--exclude=.svn' -rupN /home/kesten/VCP/Bazaar/blender/blender-svn/blender/source/blender/editors/object/object_vgroup.c /home/kesten/VCP/Bazaar/blender/features-branch/blender/source/blender/editors/object/object_vgroup.c --- /home/kesten/VCP/Bazaar/blender/blender-svn/blender/source/blender/editors/object/object_vgroup.c 2012-05-28 11:01:37.520857712 -0500 +++ /home/kesten/VCP/Bazaar/blender/features-branch/blender/source/blender/editors/object/object_vgroup.c 2012-06-25 23:40:54.148225380 -0500 @@ -34,6 +34,7 @@ #include #include #include +#include #include "MEM_guardedalloc.h" @@ -1382,6 +1383,110 @@ static void vgroup_blend(Object *ob, con } } +static int invCompare_MDeformWeights(const void *a1, const void *a2) +{ + + // qsort sorts in ascending order. We want descending order to save a memcopy + // so this compare function is inverted from the standard greater than comparison qsort needs. + // A normal compare function is called with two pointer arguments and should return an integer less than, equal to, + // or greater than zero corresponding to whether its first argument is considered less than, equal to, + // or greater than its second argument. This does the opposite. + const struct MDeformWeight *dw1=a1, *dw2=a2; + + if(dw1->weight < dw2->weight) + return 1; + else if(dw1->weight > dw2->weight) + return -1; + else if(&dw1 < &dw2) // compare addresses so we have a stable sort algorithm + return 1; + else + return -1; +} + +// wpaint_make_validmap MEM_mallocN's so we must delete later +extern char *wpaint_make_validmap(Object *ob); + +/* Used for limiting the number of influencing bones per vertex when exporting + skinned meshes. if all_deform_weights is True, limit all deform modifiers + to max_weights regardless of type, otherwise, only limit the number of influencing bones per vertex*/ +static void vertex_group_cull_num_weights(Object *ob, + const int max_weights, + const int all_deform_weights) +{ + + MDeformWeight *dw_temp, *dw_culled; + MDeformVert *dv, **dvert_array = NULL; + int i, j, dvert_tot = 0; + int numToDrop=0, bone_count=0, non_bone_count = 0; + const int use_vert_sel = (ob->type == OB_MESH && ((Mesh *)ob->data)->editflag & ME_EDIT_VERT_SEL) != 0; + char *vgroup_validmap; + + + ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + + if (dvert_array) { + /* only the active group */ + for (i = 0; i < dvert_tot; i++) { + + /* in case its not selected */ + if (!(dv = dvert_array[i])) { + continue; + } + + if(all_deform_weights) { + // keep only the largest weights, discarding the rest + // qsort will put array in descending order because of invCompare function + numToDrop = dv->totweight-max_weights; + if(numToDrop > 0) { + qsort(dv->dw, dv->totweight, sizeof(MDeformWeight), invCompare_MDeformWeights); + dw_culled = MEM_mallocN(sizeof(MDeformWeight) * (max_weights), __func__); + memcpy(dw_culled, &dv->dw[numToDrop], sizeof(MDeformWeight) * max_weights); + MEM_freeN(dv->dw); + dv->dw = dw_culled; + dv->totweight=max_weights; + } + } + else // only consider vgroups with bone modifiers attached (in vgroup_validmap) + { + vgroup_validmap = wpaint_make_validmap(ob); + + // re-pack dw array so that non-bone weights are first, bone-weighted verts at end + // sort the tail, then copy only the truncated array back to dv->dw + dw_temp = MEM_mallocN(sizeof(MDeformWeight) * (dv->totweight), __func__); + bone_count = 0; non_bone_count=0; + for(j=0; jtotweight; j++) + { + // assert dv->dw[j].def_nr <= dv->totweight + if(!vgroup_validmap[(dv->dw[j]).def_nr]) { + dw_temp[non_bone_count]=dv->dw[j]; + non_bone_count +=1; + } + else + { + dw_temp[dv->totweight-1-bone_count]=dv->dw[j]; + bone_count +=1; + } + } + // assert(bone_count+non_bone_count == totweight) + numToDrop = bone_count - max_weights; + if(numToDrop > 0) { + qsort(&dw_temp[non_bone_count], bone_count, sizeof(MDeformWeight), invCompare_MDeformWeights); + dv->totweight -= numToDrop; + // Do we want to clean/normalize here? + // How best to free the numToDrop weights? + dw_culled = MEM_mallocN(sizeof(MDeformWeight) * (dv->totweight), __func__); + memcpy(dw_culled, dw_temp, sizeof(MDeformWeight) * dv->totweight); + MEM_freeN(dv->dw); + dv->dw = dw_culled; + } + MEM_freeN(dw_temp); + MEM_freeN(vgroup_validmap); + } + } + MEM_freeN(dvert_array); + } +} + static void vgroup_clean(Object *ob, const float epsilon, int keep_single) { MDeformWeight *dw; @@ -2639,6 +2744,39 @@ void OBJECT_OT_vertex_group_clean(wmOper "Keep verts assigned to at least one group when cleaning"); } +static int vertex_group_cull_num_weights_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_context(C); + + int limit = RNA_int_get(op->ptr, "max_deform_weights"); + int all_deform_weights = RNA_boolean_get(op->ptr, "all_deform_weights"); + + vertex_group_cull_num_weights(ob, limit, all_deform_weights); + + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_vertex_group_cull_num_weights(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Limit Number of Weights per Vertex"; + ot->idname = "OBJECT_OT_vertex_group_cull_num_weights"; + ot->description = "Limits deform weights associated with a vertex to a specified number by removing lowest weights"; + + /* api callbacks */ + ot->poll = vertex_group_poll; + ot->exec = vertex_group_cull_num_weights_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_int(ot->srna, "max_deform_weights", 4, 0, 32, "Limit", "Maximum number of deform weights", 0, 32); + RNA_def_boolean(ot->srna, "all_deform_weights", FALSE, "All Deform Weights", "Cull all deform weights, not just bones"); +} static int vertex_group_mirror_exec(bContext *C, wmOperator *op) { diff '--exclude=.svn' -rupN /home/kesten/VCP/Bazaar/blender/blender-svn/blender/source/blender/editors/sculpt_paint/paint_vertex.c /home/kesten/VCP/Bazaar/blender/features-branch/blender/source/blender/editors/sculpt_paint/paint_vertex.c --- /home/kesten/VCP/Bazaar/blender/blender-svn/blender/source/blender/editors/sculpt_paint/paint_vertex.c 2012-06-16 12:12:30.160468819 -0500 +++ /home/kesten/VCP/Bazaar/blender/features-branch/blender/source/blender/editors/sculpt_paint/paint_vertex.c 2012-06-16 14:37:24.807188000 -0500 @@ -1723,7 +1723,7 @@ static int get_first_selected_nonzero_we } -static char *wpaint_make_validmap(Object *ob); +char *wpaint_make_validmap(Object *ob); static void do_weight_paint_vertex( @@ -1833,7 +1833,7 @@ static void do_weight_paint_vertex( /* apply normalize */ if (wpi->do_auto_normalize) { - /* note on normalize - this used to be applied after painting and normalize all weights, + /* note on normalize - this used to be applied after painting and normalize all weights, * in some ways this is good because there is feedback where the more weights involved would * 'resist' so you couldn't instantly zero out other weights by painting 1.0 on the active. * @@ -2067,7 +2067,7 @@ struct WPaintData { int defbase_tot; }; -static char *wpaint_make_validmap(Object *ob) +char *wpaint_make_validmap(Object *ob) { bDeformGroup *dg; ModifierData *md;