svn merge ^/trunk/blender -r40311:40338
authorCampbell Barton <ideasman42@gmail.com>
Mon, 19 Sep 2011 05:58:52 +0000 (05:58 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Mon, 19 Sep 2011 05:58:52 +0000 (05:58 +0000)
35 files changed:
build_files/cmake/config/blender_lite.cmake
release/scripts/startup/bl_ui/properties_data_mesh.py
release/scripts/startup/bl_ui/space_view3d.py
release/scripts/startup/bl_ui/space_view3d_toolbar.py
source/blender/blenkernel/BKE_armature.h
source/blender/blenkernel/BKE_paint.h
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/armature.c
source/blender/blenkernel/intern/paint.c
source/blender/editors/armature/editarmature.c
source/blender/editors/armature/meshlaplacian.c
source/blender/editors/include/ED_mesh.h
source/blender/editors/include/ED_view3d.h
source/blender/editors/interface/interface_templates.c
source/blender/editors/mesh/editmesh.c
source/blender/editors/mesh/editmesh_mods.c
source/blender/editors/object/object_intern.h
source/blender/editors/object/object_ops.c
source/blender/editors/object/object_vgroup.c
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/sculpt_paint/paint_intern.h
source/blender/editors/sculpt_paint/paint_ops.c
source/blender/editors/sculpt_paint/paint_utils.c
source/blender/editors/sculpt_paint/paint_vertex.c
source/blender/editors/space_view3d/drawmesh.c
source/blender/editors/space_view3d/drawobject.c
source/blender/editors/space_view3d/space_view3d.c
source/blender/editors/space_view3d/view3d_header.c
source/blender/editors/space_view3d/view3d_select.c
source/blender/makesdna/DNA_mesh_types.h
source/blender/makesdna/DNA_object_types.h
source/blender/makesdna/DNA_scene_types.h
source/blender/makesrna/intern/rna_mesh.c
source/blender/makesrna/intern/rna_object.c
source/blender/makesrna/intern/rna_scene.c

index f09a8058f1434b0414f3b13bef44cbfbd8e2f900..d2b791baede546d22bcdbc0b731c1a06c44ee57d 100644 (file)
@@ -1,4 +1,4 @@
-# turn everything OFF except for python which defaults to ON
+# turn everything OFF CACHE FORCE BOOL) except for python which defaults to ON
 # and is needed for the UI
 #
 # Example usage:
index 75df7dad5f2fc3be25a4c6df3cccc0e15cbdb936..a94a45958dee4f104bbeea539da4ea9638f15049 100644 (file)
@@ -35,6 +35,10 @@ class MESH_MT_vertex_group_specials(Menu):
         layout.operator("object.vertex_group_copy_to_selected", icon='LINK_AREA')
         layout.operator("object.vertex_group_mirror", icon='ARROW_LEFTRIGHT')
         layout.operator("object.vertex_group_remove", icon='X', text="Delete All").all = True
+        layout.separator()
+        layout.operator("object.vertex_group_lock", icon='LOCK', text="Lock All").action = 'SELECT'
+        layout.operator("object.vertex_group_lock", icon='UNLOCK', text="UnLock All").action = 'DESELECT'
+        layout.operator("object.vertex_group_lock", icon='LOCK', text="Lock Invert All").action = 'INVERT'
 
 
 class MESH_MT_shape_key_specials(Menu):
index 9f96df1eb6694b23695da46c0d080e093eae6bc4..357c673edbd72c78df122255c4cc01e8e79136e2 100644 (file)
@@ -1072,6 +1072,7 @@ class VIEW3D_MT_paint_weight(Menu):
         layout.operator("object.vertex_group_invert", text="Invert")
         layout.operator("object.vertex_group_clean", text="Clean")
         layout.operator("object.vertex_group_levels", text="Levels")
+        layout.operator("object.vertex_group_fix", text="Fix Deforms")
 
         layout.separator()
 
index 4b2ee57df68b2b7cab605acdb81de1e0706c575a..e322a6dcd13838908a5828d3d2988d433267fe7b 100644 (file)
@@ -646,6 +646,7 @@ class VIEW3D_PT_tools_brush(PaintPanel, Panel):
         elif context.weight_paint_object and brush:
             layout.prop(context.tool_settings, "vertex_group_weight", text="Weight", slider=True)
             layout.prop(context.tool_settings, "use_auto_normalize", text="Auto Normalize")
+            layout.prop(context.tool_settings, "use_multipaint", text="Multi-Paint")
 
             col = layout.column()
 
@@ -1058,6 +1059,7 @@ class VIEW3D_PT_tools_weightpaint(View3DPanel, Panel):
         col.operator("object.vertex_group_invert", text="Invert")
         col.operator("object.vertex_group_clean", text="Clean")
         col.operator("object.vertex_group_levels", text="Levels")
+        col.operator("object.vertex_group_fix", text="Fix Deforms")
 
 
 class VIEW3D_PT_tools_weightpaint_options(View3DPanel, Panel):
index 7d60c00156dba4ad7777ed9943d5477f6276baaa..8836999bc9b91ddaf9edb437978ac5b729a6ae11 100644 (file)
@@ -100,6 +100,8 @@ void get_objectspace_bone_matrix (struct Bone* bone, float M_accumulatedMatrix[]
 void vec_roll_to_mat3(float *vec, float roll, float mat[][3]);
 void mat3_to_vec_roll(float mat[][3], float *vec, float *roll);
 
+int get_selected_defgroups(struct Object *ob, char *defbase_sel, int defbase_len);
+
 /* Common Conversions Between Co-ordinate Spaces */
 void armature_mat_world_to_pose(struct Object *ob, float inmat[][4], float outmat[][4]);
 void armature_loc_world_to_pose(struct Object *ob, float *inloc, float *outloc);
index 0400f229083e360d3cec8c08c14301186643dbd3..2578a90808aad729ceead4d84d975262f3ecee26 100644 (file)
@@ -59,6 +59,7 @@ void paint_brush_set(struct Paint *paint, struct Brush *br);
  * Texture paint could be removed since selected faces are not used
  * however hiding faces is useful */
 int paint_facesel_test(struct Object *ob);
+int paint_vertsel_test(struct Object *ob);
 
 /* Session data (mode-specific) */
 
index 7a02da57350b51f234feb952cd48b325ee997e35..1660ac29217bc19c9be5284b7b8b0d77e0e6da8f 100644 (file)
@@ -40,6 +40,7 @@
 #include "DNA_cloth_types.h"
 #include "DNA_key_types.h"
 #include "DNA_meshdata_types.h"
+#include "DNA_armature_types.h"
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h" // N_T
 
@@ -59,6 +60,7 @@
 #include "BKE_paint.h"
 #include "BKE_texture.h"
 #include "BKE_multires.h"
+#include "BKE_armature.h"
 
 #include "BLO_sys_types.h" // for intptr_t support
 
@@ -1673,20 +1675,64 @@ void weight_to_rgb(float input, float *fr, float *fg, float *fb)
        }
 }
 
-static void calc_weightpaint_vert_color(Object *ob, ColorBand *coba, int vert, unsigned char *col)
+/* draw_flag's for calc_weightpaint_vert_color */
+enum {
+       CALC_WP_MULTIPAINT= (1<<0),
+       CALC_WP_AUTO_NORMALIZE= (1<<1),
+};
+
+static void calc_weightpaint_vert_color(Object *ob, ColorBand *coba, int vert, unsigned char *col, char *dg_flags, int selected, int UNUSED(unselected), const int draw_flag)
 {
        Mesh *me = ob->data;
        float colf[4], input = 0.0f;
        int i;
 
+       
+       int make_black= FALSE;
+
        if (me->dvert) {
-               for (i=0; i<me->dvert[vert].totweight; i++)
-                       if (me->dvert[vert].dw[i].def_nr==ob->actdef-1)
-                               input+=me->dvert[vert].dw[i].weight;            
-       }
+               if ((selected > 1) && (draw_flag & CALC_WP_MULTIPAINT)) {
+                       
+                       int was_a_nonzero= FALSE;
+                       for (i=0; i<me->dvert[vert].totweight; i++) {
+                               /* in multipaint, get the average if auto normalize is inactive
+                                * get the sum if it is active */
+                               if(dg_flags[me->dvert[vert].dw[i].def_nr]) {
+                                       if(me->dvert[vert].dw[i].weight) {
+                                               input+= me->dvert[vert].dw[i].weight;
+                                               was_a_nonzero= TRUE;
+                                       }
+                               }
+                       }
 
-       CLAMP(input, 0.0f, 1.0f);
+                       /* make it black if the selected groups have no weight on a vertex */
+                       if(was_a_nonzero == FALSE) {
+                               make_black = TRUE;
+                       }
+                       else if ((draw_flag & CALC_WP_AUTO_NORMALIZE) == FALSE) {
+                               input /= selected; /* get the average */
+                       }
+               }
+               else {
+                       /* default, non tricky behavior */
+                       for (i=0; i<me->dvert[vert].totweight; i++) {
+                               if (me->dvert[vert].dw[i].def_nr==ob->actdef-1) {
+                                       input+=me->dvert[vert].dw[i].weight;
+                               }
+                       }
+               }
+       }
        
+       if (make_black) {
+               col[3] = 0;
+               col[2] = 0;
+               col[1] = 0;
+               col[0] = 255;
+               return;
+       }
+
+       CLAMP(input, 0.0f, 1.0f);       
+
        if(coba)
                do_colorband(coba, input, colf);
        else
@@ -1705,7 +1751,7 @@ void vDM_ColorBand_store(ColorBand *coba)
        stored_cb= coba;
 }
 
-static void add_weight_mcol_dm(Object *ob, DerivedMesh *dm)
+static void add_weight_mcol_dm(Object *ob, DerivedMesh *dm, int const draw_flag)
 {
        Mesh *me = ob->data;
        MFace *mf = me->mface;
@@ -1713,17 +1759,24 @@ static void add_weight_mcol_dm(Object *ob, DerivedMesh *dm)
        unsigned char *wtcol;
        int i;
        
+       int defbase_len = BLI_countlist(&ob->defbase);
+       char *defbase_sel = MEM_mallocN(defbase_len * sizeof(char), __func__);
+       int selected = get_selected_defgroups(ob, defbase_sel, defbase_len);
+       int unselected = defbase_len - selected;
+
        wtcol = MEM_callocN (sizeof (unsigned char) * me->totface*4*4, "weightmap");
        
        memset(wtcol, 0x55, sizeof (unsigned char) * me->totface*4*4);
        for (i=0; i<me->totface; i++, mf++) {
-               calc_weightpaint_vert_color(ob, coba, mf->v1, &wtcol[(i*4 + 0)*4]); 
-               calc_weightpaint_vert_color(ob, coba, mf->v2, &wtcol[(i*4 + 1)*4]); 
-               calc_weightpaint_vert_color(ob, coba, mf->v3, &wtcol[(i*4 + 2)*4]); 
+               calc_weightpaint_vert_color(ob, coba, mf->v1, &wtcol[(i*4 + 0)*4], defbase_sel, selected, unselected, draw_flag);
+               calc_weightpaint_vert_color(ob, coba, mf->v2, &wtcol[(i*4 + 1)*4], defbase_sel, selected, unselected, draw_flag);
+               calc_weightpaint_vert_color(ob, coba, mf->v3, &wtcol[(i*4 + 2)*4], defbase_sel, selected, unselected, draw_flag);
                if (mf->v4)
-                       calc_weightpaint_vert_color(ob, coba, mf->v4, &wtcol[(i*4 + 3)*4]); 
+                       calc_weightpaint_vert_color(ob, coba, mf->v4, &wtcol[(i*4 + 3)*4], defbase_sel, selected, unselected, draw_flag);
        }
        
+       MEM_freeN(defbase_sel);
+
        CustomData_add_layer(&dm->faceData, CD_WEIGHT_MCOL, CD_ASSIGN, wtcol, dm->numFaceData);
 }
 
@@ -1751,6 +1804,9 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
        int has_multires = mmd != NULL, multires_applied = 0;
        int sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt;
 
+       int draw_flag= ((scene->toolsettings->multipaint ? CALC_WP_MULTIPAINT : 0) |
+                       (scene->toolsettings->auto_normalize ? CALC_WP_AUTO_NORMALIZE : 0));
+
        if(mmd && !mmd->sculptlvl)
                has_multires = 0;
 
@@ -1930,7 +1986,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                                }
 
                                if((dataMask & CD_MASK_WEIGHT_MCOL) && (ob->mode & OB_MODE_WEIGHT_PAINT))
-                                       add_weight_mcol_dm(ob, dm);
+                                       add_weight_mcol_dm(ob, dm, draw_flag); 
 
                                /* Constructive modifiers need to have an origindex
                                 * otherwise they wont have anywhere to copy the data from.
@@ -2042,7 +2098,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                CDDM_calc_normals(finaldm);
 
                if((dataMask & CD_MASK_WEIGHT_MCOL) && (ob->mode & OB_MODE_WEIGHT_PAINT))
-                       add_weight_mcol_dm(ob, finaldm);
+                       add_weight_mcol_dm(ob, finaldm, draw_flag);
        } else if(dm) {
                finaldm = dm;
        } else {
@@ -2054,7 +2110,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                }
 
                if((dataMask & CD_MASK_WEIGHT_MCOL) && (ob->mode & OB_MODE_WEIGHT_PAINT))
-                       add_weight_mcol_dm(ob, finaldm);
+                       add_weight_mcol_dm(ob, finaldm, draw_flag);
        }
 
        /* add an orco layer if needed */
@@ -2327,7 +2383,7 @@ static void clear_mesh_caches(Object *ob)
 static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask)
 {
        Object *obact = scene->basact?scene->basact->object:NULL;
-       int editing = paint_facesel_test(ob);
+       int editing = paint_facesel_test(ob) || paint_vertsel_test(ob);/* paint_vertsel_test */
        /* weight paint and face select need original indices because of selection buffer drawing */
        int needMapping = (ob==obact) && (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT|OB_MODE_VERTEX_PAINT)));
 
index 08a95477c2e0f83185d1341f929c0f40290e9377..1149d8eee258094177cdeaecae53824f417ccc70 100644 (file)
@@ -2464,3 +2464,33 @@ void where_is_pose (Scene *scene, Object *ob)
                }
        }
 }
+
+
+/* Returns total selected vgroups,
+ * wpi.defbase_sel is assumed malloc'd, all values are set */
+int get_selected_defgroups(Object *ob, char *dg_selection, int defbase_len)
+{
+       bDeformGroup *defgroup;
+       unsigned int i;
+       Object *armob= object_pose_armature_get(ob);
+       int dg_flags_sel_tot= 0;
+
+       if(armob) {
+               bPose *pose= armob->pose;
+               for (i= 0, defgroup= ob->defbase.first; i < defbase_len && defgroup; defgroup = defgroup->next, i++) {
+                       bPoseChannel *pchan= get_pose_channel(pose, defgroup->name);
+                       if(pchan && (pchan->bone->flag & BONE_SELECTED)) {
+                               dg_selection[i]= TRUE;
+                               dg_flags_sel_tot++;
+                       }
+                       else {
+                               dg_selection[i]= FALSE;
+                       }
+               }
+       }
+       else {
+               memset(dg_selection, FALSE, sizeof(char) * defbase_len);
+       }
+
+       return dg_flags_sel_tot;
+}
index d00eb6192da6e59ad65f0841a716f9964c10ad5b..ddeb42d608e0c8e0432152c53eb28c3c54467b5a 100644 (file)
@@ -97,6 +97,10 @@ int paint_facesel_test(Object *ob)
        return (ob && ob->type==OB_MESH && ob->data && (((Mesh *)ob->data)->editflag & ME_EDIT_PAINT_MASK) && (ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT)));
 }
 
+int paint_vertsel_test(Object *ob)
+{
+       return (ob && ob->type==OB_MESH && ob->data && (((Mesh *)ob->data)->editflag & ME_EDIT_VERT_SEL) && (ob->mode & OB_MODE_WEIGHT_PAINT));
+}
 void paint_init(Paint *p, const char col[3])
 {
        Brush *brush;
index eafe65b4492e55a15786b683cd0600191d057e59..d023889c89a3940293370377626b49ca67d02390 100644 (file)
@@ -4290,10 +4290,15 @@ int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, shor
        
        /* if the bone cannot be affected, don't do anything */
        if ((nearBone) && !(nearBone->flag & BONE_UNSELECTABLE)) {
+               Object *ob_act= OBACT;
                bArmature *arm= ob->data;
                
-               /* since we do unified select, we don't shift+select a bone if the armature object was not active yet */
-               if (!(extend) || (base != scene->basact)) {
+               /* since we do unified select, we don't shift+select a bone if the
+                * armature object was not active yet.
+                * note, special exception for armature mode so we can do multi-select
+                * we could check for multi-select explicitly but think its fine to
+                * always give pradictable behavior in weight paint mode - campbell */
+               if (!(extend) || (base->object != ob_act && !(ob_act->mode & OB_MODE_WEIGHT_PAINT))) {
                        ED_pose_deselectall(ob, 0);
                        nearBone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
                        arm->act_bone= nearBone;
@@ -4324,7 +4329,7 @@ int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, shor
                }
                
                /* in weightpaint we select the associated vertex group too */
-               if (OBACT && OBACT->mode & OB_MODE_WEIGHT_PAINT) {
+               if (ob_act && ob_act->mode & OB_MODE_WEIGHT_PAINT) {
                        if (nearBone == arm->act_bone) {
                                ED_vgroup_select_by_name(OBACT, nearBone->name);
                                DAG_id_tag_update(&OBACT->id, OB_RECALC_DATA);
@@ -5061,6 +5066,10 @@ void POSE_OT_select_inverse(wmOperatorType *ot)
 static int pose_de_select_all_exec(bContext *C, wmOperator *op)
 {
        int action = RNA_enum_get(op->ptr, "action");
+       
+       Object *ob = NULL;
+       Scene *scene= CTX_data_scene(C);
+       int multipaint = scene->toolsettings->multipaint;
 
        if (action == SEL_TOGGLE) {
                action= CTX_DATA_COUNT(C, selected_pose_bones) ? SEL_DESELECT : SEL_SELECT;
@@ -5091,6 +5100,11 @@ static int pose_de_select_all_exec(bContext *C, wmOperator *op)
 
        WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, NULL);
        
+       if(multipaint) {
+               ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+               DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+       }
+
        return OPERATOR_FINISHED;
 }
 
index 48ca6d6fd72d8887f7d9cbaf902cf7ed98a50fac..45caf41f438ff6f3a9aaab476211bb8d837ec5ec 100644 (file)
@@ -657,22 +657,41 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource,
        int *vertsflipped = NULL, *mask= NULL;
        int a, totface, j, bbone, firstsegment, lastsegment;
 
+       MVert *mvert = me->mvert;
+       int use_vert_sel= FALSE;
+       int use_face_sel= FALSE;
+
        *err_str= NULL;
 
        /* count triangles and create mask */
-       if(me->editflag & ME_EDIT_PAINT_MASK)
+       if(     (use_face_sel= (me->editflag & ME_EDIT_PAINT_MASK) != 0) ||
+               (use_vert_sel= ((me->editflag & ME_EDIT_VERT_SEL) != 0)))
+       {
                mask= MEM_callocN(sizeof(int)*me->totvert, "heat_bone_weighting mask");
+       }
 
        for(totface=0, a=0, mface=me->mface; a<me->totface; a++, mface++) {
                totface++;
                if(mface->v4) totface++;
 
-               if(mask && (mface->flag & ME_FACE_SEL)) {
-                       mask[mface->v1]= 1;
-                       mask[mface->v2]= 1;
-                       mask[mface->v3]= 1;
-                       if(mface->v4)
-                               mask[mface->v4]= 1;
+               /*  (added selectedVerts content for vertex mask, they used to just equal 1) */
+               if(use_vert_sel) {
+                       mask[mface->v1]= (mvert[mface->v1].flag & SELECT) != 0;
+                       mask[mface->v2]= (mvert[mface->v2].flag & SELECT) != 0;
+                       mask[mface->v3]= (mvert[mface->v3].flag & SELECT) != 0;
+                       if(mface->v4) {
+                               mask[mface->v4]= (mvert[mface->v4].flag & SELECT) != 0;
+                       }
+               }
+               else {
+                       if(use_face_sel) {
+                               mask[mface->v1]= 1;
+                               mask[mface->v2]= 1;
+                               mask[mface->v3]= 1;
+                               if(mface->v4) {
+                                       mask[mface->v4]= 1;
+                               }
+                       }
                }
        }
 
index 8bb77ad43a04710418d8bb964a593ecf5f7f9dbe..9709979ff6a912dd911021c74077f0be37897047 100644 (file)
@@ -123,6 +123,8 @@ int                 EM_vertColorCheck(struct EditMesh *em);
 
 void           undo_push_mesh(struct bContext *C, const char *name);
 
+void           paintvert_flush_flags(struct Object *ob);
+void           paintvert_deselect_all_visible(struct Object *ob, int action, short flush_flags);
 
 /* editmesh_lib.c */
 
index f8682d3935b273493fde1878d1fe70485a02e293..d574ddd30309cd8d204da188a4a77fb370bab055 100644 (file)
@@ -53,6 +53,7 @@ struct Scene;
 struct View3D;
 struct ViewContext;
 struct wmWindow;
+struct MVert;
 
 
 /* for derivedmesh drawing callbacks, for view3d_select, .... */
index 8c151712f959f3792ed169c601f2208c58d89fce..b1d0b73b2b1828622758cd18c39e3e8eee063cef 100644 (file)
@@ -2124,6 +2124,18 @@ static void list_item_row(bContext *C, uiLayout *layout, PointerRNA *ptr, Pointe
                //uiItemR(row, itemptr, "mute", 0, "", ICON_MUTE_IPO_OFF);
                uiBlockSetEmboss(block, UI_EMBOSS);
        }
+       else if(itemptr->type == &RNA_VertexGroup) {
+               bDeformGroup *dg= (bDeformGroup *)itemptr->data;
+               uiItemL(sub, name, icon);
+               /* RNA does not allow nice lock icons, use lower level buttons */
+#if 0
+               uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "lock_weight", 0, 0, 0, 0, 0,  NULL);
+#else
+               uiBlockSetEmboss(block, UI_EMBOSSN);
+               uiDefIconButBitC(block, TOG, DG_LOCK_WEIGHT, 0, (dg->flag & DG_LOCK_WEIGHT) ? ICON_LOCKED : ICON_UNLOCKED, 0, 0, UI_UNIT_X, UI_UNIT_Y, &dg->flag, 0, 0, 0, 0, "Maintain relative weights while painting");
+               uiBlockSetEmboss(block, UI_EMBOSS);
+#endif
+       }
        else if(itemptr->type == &RNA_KeyingSetPath) {
                KS_Path *ksp = (KS_Path*)itemptr->data;
                
index 9bf863faae328aa89587e09ad3b49cd9e7fb3d15..1ff46ddb546ea6bc6f00d37a3a21a8e5de6fcfad 100644 (file)
@@ -1958,3 +1958,101 @@ void em_setup_viewcontext(bContext *C, ViewContext *vc)
                vc->em= me->edit_mesh;
        }
 }
+
+
+/*  (similar to void paintface_flush_flags(Object *ob))
+ * copy the vertex flags, most importantly selection from the mesh to the final derived mesh,
+ * use in object mode when selecting vertices (while painting) */
+void paintvert_flush_flags(Object *ob)
+{
+       Mesh *me= get_mesh(ob);
+       DerivedMesh *dm= ob->derivedFinal;
+       MVert *dm_mvert, *dm_mv;
+       int *index_array = NULL;
+       int totvert;
+       int i;
+
+       if(me==NULL || dm==NULL)
+               return;
+
+       index_array = dm->getVertDataArray(dm, CD_ORIGINDEX);
+
+       dm_mvert = dm->getVertArray(dm);
+       totvert = dm->getNumVerts(dm);
+
+       dm_mv= dm_mvert;
+
+       if(index_array) {
+               int orig_index;
+               for (i= 0; i<totvert; i++, dm_mv++) {
+                       orig_index= index_array[i];
+                       if(orig_index != ORIGINDEX_NONE) {
+                               dm_mv->flag= me->mvert[index_array[i]].flag;
+                       }
+               }
+       }
+       else {
+               for (i= 0; i<totvert; i++, dm_mv++) {
+                       dm_mv->flag= me->mvert[i].flag;
+               }
+       }
+}
+/*  note: if the caller passes FALSE to flush_flags, then they will need to run paintvert_flush_flags(ob) themselves */
+void paintvert_deselect_all_visible(Object *ob, int action, short flush_flags)
+{
+       Mesh *me;
+       MVert *mvert;
+       int a;
+
+       me= get_mesh(ob);
+       if(me==NULL) return;
+       
+       if(action == SEL_INVERT) {
+               mvert= me->mvert;
+               a= me->totvert;
+               while(a--) {
+                       if((mvert->flag & ME_HIDE) == 0) {
+                               mvert->flag ^= SELECT;
+                       }
+                       mvert++;
+               }
+       }
+       else {
+               if (action == SEL_TOGGLE) {
+                       action = SEL_SELECT;
+
+                       mvert= me->mvert;
+                       a= me->totvert;
+                       while(a--) {
+                               if((mvert->flag & ME_HIDE) == 0 && mvert->flag & SELECT) {
+                                       action = SEL_DESELECT;
+                                       break;
+                               }
+                               mvert++;
+                       }
+               }
+
+               mvert= me->mvert;
+               a= me->totvert;
+               while(a--) {
+                       if((mvert->flag & ME_HIDE) == 0) {
+                               switch (action) {
+                               case SEL_SELECT:
+                                       mvert->flag |= SELECT;
+                                       break;
+                               case SEL_DESELECT:
+                                       mvert->flag &= ~SELECT;
+                                       break;
+                               case SEL_INVERT:
+                                       mvert->flag ^= SELECT;
+                                       break;
+                               }
+                       }
+                       mvert++;
+               }
+       }
+
+       if(flush_flags) {
+               paintvert_flush_flags(ob);
+       }
+}
\ No newline at end of file
index 7af4ebee3bc16a323b0667e2b359bf66ba78603e..f7c2f895ba575cd3d6c808b41e249d17d060cb84 100644 (file)
@@ -266,6 +266,7 @@ int EM_mask_init_backbuf_border(ViewContext *vc, int mcords[][2], short tot, sho
        /* method in use for face selecting too */
        if(vc->obedit==NULL) {
                if(paint_facesel_test(vc->obact));
+               else if(paint_vertsel_test(vc->obact));
                else return 0;
        }
        else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
@@ -328,6 +329,7 @@ int EM_init_backbuf_circle(ViewContext *vc, short xs, short ys, short rads)
        /* method in use for face selecting too */
        if(vc->obedit==NULL) {
                if(paint_facesel_test(vc->obact));
+               else if (paint_vertsel_test(vc->obact));
                else return 0;
        }
        else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
index 3da0723ec1811210d8c5f863fdff454b52d7daaa..434111c12277b6045d667af6858473b02b893e4a 100644 (file)
@@ -200,6 +200,8 @@ void OBJECT_OT_vertex_group_copy(struct wmOperatorType *ot);
 void OBJECT_OT_vertex_group_normalize(struct wmOperatorType *ot);
 void OBJECT_OT_vertex_group_normalize_all(struct wmOperatorType *ot);
 void OBJECT_OT_vertex_group_levels(struct wmOperatorType *ot);
+void OBJECT_OT_vertex_group_lock(struct wmOperatorType *ot);
+void OBJECT_OT_vertex_group_fix(struct wmOperatorType *ot);
 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);
index 5eb17268d195ed9e15baa01f8e3fc9fe96663d5f..12cb05637a70d719b4c8eca2d314aa926928a08c 100644 (file)
@@ -174,6 +174,8 @@ void ED_operatortypes_object(void)
        WM_operatortype_append(OBJECT_OT_vertex_group_copy);
        WM_operatortype_append(OBJECT_OT_vertex_group_normalize);
        WM_operatortype_append(OBJECT_OT_vertex_group_normalize_all);
+       WM_operatortype_append(OBJECT_OT_vertex_group_lock);
+       WM_operatortype_append(OBJECT_OT_vertex_group_fix);
        WM_operatortype_append(OBJECT_OT_vertex_group_invert);
        WM_operatortype_append(OBJECT_OT_vertex_group_levels);
        WM_operatortype_append(OBJECT_OT_vertex_group_blend);
index 52ba9460818d26c0aec13f36172afcb6aacf36f7..2a3cdd015faeeee7074ccc34beaea9d72bb85840 100644 (file)
@@ -49,6 +49,7 @@
 #include "DNA_scene_types.h"
 #include "DNA_particle_types.h"
 
+#include "BLI_math.h"
 #include "BLI_blenlib.h"
 #include "BLI_editVert.h"
 #include "BLI_utildefines.h"
@@ -60,6 +61,7 @@
 #include "BKE_global.h"
 #include "BKE_mesh.h"
 #include "BKE_report.h"
+#include "BKE_DerivedMesh.h"
 
 #include "RNA_access.h"
 #include "RNA_define.h"
@@ -701,6 +703,10 @@ static void vgroup_normalize(Object *ob)
        MDeformWeight *dw;
        MDeformVert *dvert, **dvert_array=NULL;
        int i, def_nr, dvert_tot=0;
+       
+       Mesh *me = ob->data;
+       MVert *mvert = me->mvert;
+       const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
 
        ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
 
@@ -712,6 +718,11 @@ static void vgroup_normalize(Object *ob)
                def_nr= ob->actdef-1;
 
                for(i = 0; i < dvert_tot; i++) {
+                       
+                       if(use_vert_sel && !(mvert[i].flag & SELECT)) {
+                               continue;
+                       }
+
                        dvert = dvert_array[i];
                        dw = defvert_find_index(dvert, def_nr);
                        if(dw) {
@@ -721,6 +732,11 @@ static void vgroup_normalize(Object *ob)
 
                if(weight_max > 0.0f) {
                        for(i = 0; i < dvert_tot; i++) {
+                               
+                               if(use_vert_sel && !(mvert[i].flag & SELECT)) {
+                                       continue;
+                               }
+
                                dvert = dvert_array[i];
                                dw = defvert_find_index(dvert, def_nr);
                                if(dw) {
@@ -736,6 +752,401 @@ static void vgroup_normalize(Object *ob)
        if (dvert_array) MEM_freeN(dvert_array);
 }
 
+/* This adds the indices of vertices to a list if they are not already present
+It returns the number that it added (0-2)
+It relies on verts having -1 for unassigned indices
+*/
+static int tryToAddVerts(int *verts, int length, int a, int b) {
+       char containsA = FALSE;
+       char containsB = FALSE;
+       int added = 0;
+       int i;
+       for(i = 0; i < length && (!containsA || !containsB); i++) {
+               if(verts[i] == a) {
+                       containsA = TRUE;
+               } else if(verts[i] == b) {
+                       containsB = TRUE;
+               } else if(verts[i] == -1) {
+                       if(!containsA) {
+                               verts[i] = a;
+                               containsA = TRUE;
+                               added++;
+                       } else if(!containsB){
+                               verts[i] = b;
+                               containsB = TRUE;
+                               added++;
+                       }
+               }
+       }
+       return added;
+}
+
+/* This finds all of the vertices connected to vert by an edge
+and returns an array of indices of size count
+
+count is an int passed by reference so it can be assigned the value of the length here.
+*/
+static int* getSurroundingVerts(Mesh *me, int vert, int *count) {
+       int length = 0;
+       int *tverts;
+       int *verts = NULL;
+       MFace *mf = me->mface;
+       int totface = me->totface;
+       int found = 0;
+       int i;
+       for(i = 0; i < totface; i++, mf++) {
+               if(vert == mf->v1 || vert == mf->v2 || vert == mf->v3 || (mf->v4 &&vert == mf->v4)) {
+                       length+=2;
+               }
+       }
+       if(!length) {
+               return 0;
+       }
+       tverts = MEM_mallocN(sizeof(int)*length, "tempSurroundingVerts");
+       mf = me->mface;
+       for(i = 0; i < length; i++) {
+               tverts[i] = -1;
+       }
+       for(i = 0; i < totface; i++, mf++) {
+               int a=-1, b=-1;
+               if(mf->v1 == vert) {
+                       a = mf->v2;
+                       if(mf->v4) {
+                               b = mf->v4;
+                       } else {
+                               b = mf->v3;
+                       }
+               } else if(mf->v2 == vert) {
+                       a = mf->v1;
+                       b = mf->v3;
+               } else if(mf->v3 == vert) {
+                       a = mf->v2;
+                       if(mf->v4) {
+                               b = mf->v4;
+                       } else {
+                               b = mf->v1;
+                       }
+               } else if (mf->v4 && mf->v4 == vert){
+                       a = mf->v1;
+                       b = mf->v3;
+               } else {
+                       continue;
+               }
+               found += tryToAddVerts(tverts, length, a, b);
+       }
+       if(found) {
+               verts = MEM_mallocN(sizeof(int)* found, "surroundingVerts");
+               for(i = 0; i < found; i++) {
+                       verts[i] = tverts[i];
+               }
+               *count = found;
+       }
+       MEM_freeN(tverts);
+       return verts;
+}
+
+/* get a single point in space by averaging a point cloud (vectors of size 3)
+coord is the place the average is stored, points is the point cloud, count is the number of points in the cloud
+*/
+static void getSingleCoordinate(MVert *points, int count, float coord[3]) {
+       int i;
+       zero_v3(coord);
+       for(i = 0; i < count; i++) {
+               add_v3_v3(coord, points[i].co);
+       }
+       mul_v3_fl(coord, 1.0f/count);
+}
+
+/* find the closest point on a plane to another point and store it in dst */
+/* coord is a point on the plane */
+/* point is the point that you want the nearest of */
+/* norm is the plane's normal, and d is the last number in the plane equation 0 = ax + by + cz + d */
+static void getNearestPointOnPlane(const float norm[3], const float coord[3], const float point[3], float dst_r[3])
+{
+       float temp[3];
+       float dotprod;
+
+       sub_v3_v3v3(temp, point, coord);
+       dotprod= dot_v3v3(temp, norm);
+
+       dst_r[0] = point[0] - (norm[0] * dotprod);
+       dst_r[1] = point[1] - (norm[1] * dotprod);
+       dst_r[2] = point[2] - (norm[2] * dotprod);
+}
+
+/* distance of two vectors a and b of size length */
+static float distance(float* a, float *b, int length) {
+       int i;
+       float sum = 0;
+       for(i = 0; i < length; i++) {
+               sum += (b[i]-a[i])*(b[i]-a[i]);
+       }
+       return sqrt(sum);
+}
+
+/* given a plane and a start and end position,
+compute the amount of vertical distance relative to the plane and store it in dists,
+then get the horizontal and vertical change and store them in changes
+*/
+static void getVerticalAndHorizontalChange(float *norm, float d, float *coord, float *start, float distToStart, float *end, float (*changes)[2], float *dists, int index) {
+       // A=Q-((Q-P).N)N
+       // D = (a*x0 + b*y0 +c*z0 +d)
+       float projA[3] = {0}, projB[3] = {0};
+
+       getNearestPointOnPlane(norm, coord, start, projA);
+       getNearestPointOnPlane(norm, coord, end, projB);
+       // (vertical and horizontal refer to the plane's y and xz respectively)
+       // vertical distance
+       dists[index] = norm[0]*end[0] + norm[1]*end[1] + norm[2]*end[2] + d;
+       // vertical change
+       changes[index][0] = dists[index] - distToStart;
+       //printf("vc %f %f\n", distance(end, projB, 3)-distance(start, projA, 3), changes[index][0]);
+       // horizontal change
+       changes[index][1] = distance(projA, projB, 3);
+}
+
+// I need the derived mesh to be forgotten so the positions are recalculated with weight changes (see dm_deform_recalc)
+static void dm_deform_clear(DerivedMesh *dm, Object *ob) {
+       if(ob->derivedDeform && (ob->derivedDeform)==dm) {
+               ob->derivedDeform->needsFree = 1;
+               ob->derivedDeform->release(ob->derivedDeform);
+               ob->derivedDeform = NULL;
+       }
+       else if(dm) {
+               dm->needsFree = 1;
+               dm->release(dm);
+       }
+}
+
+// recalculate the deformation
+static DerivedMesh* dm_deform_recalc(Scene *scene, Object *ob) {
+       return mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
+}
+
+/* by changing nonzero weights, try to move a vertex in me->mverts with index 'index' to distToBe distance away from the provided plane
+strength can change distToBe so that it moves towards distToBe by that percentage
+cp changes how much the weights are adjusted to check the distance
+
+index is the index of the vertex being moved
+norm and d are the plane's properties for the equation: ax + by + cz + d = 0
+coord is a point on the plane
+*/
+static void moveCloserToDistanceFromPlane(Scene *scene, Object *ob, Mesh *me, int index, float norm[3], float coord[3], float d, float distToBe, float strength, float cp) {
+       DerivedMesh *dm;
+       MDeformWeight *dw;
+       MVert m;
+       MDeformVert *dvert = me->dvert+index;
+       int totweight = dvert->totweight;
+       float oldw = 0;
+       float oldPos[3] = {0};
+       float vc, hc, dist;
+       int i, k;
+       float (*changes)[2] = MEM_mallocN(sizeof(float *)*totweight*2, "vertHorzChange");
+       float *dists = MEM_mallocN(sizeof(float)*totweight, "distance");
+       int *upDown = MEM_callocN(sizeof(int)*totweight, "upDownTracker");// track if up or down moved it closer for each bone
+       int *dwIndices = MEM_callocN(sizeof(int)*totweight, "dwIndexTracker");
+       float distToStart;
+       int bestIndex = 0;
+       char wasChange;
+       char wasUp;
+       int lastIndex = -1;
+       float originalDistToBe = distToBe;
+       do {
+               wasChange = FALSE;
+               dm = dm_deform_recalc(scene, ob);
+               dm->getVert(dm, index, &m);
+               oldPos[0] = m.co[0];
+               oldPos[1] = m.co[1];
+               oldPos[2] = m.co[2];
+               distToStart = norm[0]*oldPos[0] + norm[1]*oldPos[1] + norm[2]*oldPos[2] + d;
+
+               if(distToBe == originalDistToBe) {
+                       distToBe += distToStart - distToStart*strength;
+               }
+               for(i = 0; i < totweight; i++) {
+                       dwIndices[i] = i;
+                       dw = (dvert->dw+i);
+                       vc = hc = 0;
+                       if(!dw->weight) {
+                               changes[i][0] = 0;
+                               changes[i][1] = 0;
+                               dists[i] = distToStart;
+                               continue;
+                       }
+                       for(k = 0; k < 2; k++) {
+                               if(dm) {
+                                       dm_deform_clear(dm, ob); dm = NULL;
+                               }
+                               oldw = dw->weight;
+                               if(k) {
+                                       dw->weight *= 1+cp;
+                               } else {
+                                       dw->weight /= 1+cp;
+                               }
+                               if(dw->weight == oldw) {
+                                       changes[i][0] = 0;
+                                       changes[i][1] = 0;
+                                       dists[i] = distToStart;
+                                       break;
+                               }
+                               if(dw->weight > 1) {
+                                       dw->weight = 1;
+                               }
+                               dm = dm_deform_recalc(scene, ob);
+                               dm->getVert(dm, index, &m);
+                               getVerticalAndHorizontalChange(norm, d, coord, oldPos, distToStart, m.co, changes, dists, i);
+                               dw->weight = oldw;
+                               if(!k) {
+                                       vc = changes[i][0];
+                                       hc = changes[i][1];
+                                       dist = dists[i];
+                               } else {
+                                       if(fabs(dist - distToBe) < fabs(dists[i] - distToBe)) {
+                                               upDown[i] = 0;
+                                               changes[i][0] = vc;
+                                               changes[i][1] = hc;
+                                               dists[i] = dist;
+                                       } else {
+                                               upDown[i] = 1;
+                                       }
+                                       if(fabs(dists[i] - distToBe) > fabs(distToStart - distToBe)) {
+                                               changes[i][0] = 0;
+                                               changes[i][1] = 0;
+                                               dists[i] = distToStart;
+                                       }
+                               }
+                       }
+               }
+               // sort the changes by the vertical change
+               for(k = 0; k < totweight; k++) {
+                       float tf;
+                       int ti;
+                       bestIndex = k;
+                       for(i = k+1; i < totweight; i++) {
+                               dist = dists[i];
+
+                               if(fabs(dist) > fabs(dists[i])) {
+                                       bestIndex = i;
+                               }
+                       }
+                       // switch with k
+                       if(bestIndex != k) {
+                               ti = upDown[k];
+                               upDown[k] = upDown[bestIndex];
+                               upDown[bestIndex] = ti;
+
+                               ti = dwIndices[k];
+                               dwIndices[k] = dwIndices[bestIndex];
+                               dwIndices[bestIndex] = ti;
+
+                               tf = changes[k][0];
+                               changes[k][0] = changes[bestIndex][0];
+                               changes[bestIndex][0] = tf;
+
+                               tf = changes[k][1];
+                               changes[k][1] = changes[bestIndex][1];
+                               changes[bestIndex][1] = tf;
+
+                               tf = dists[k];
+                               dists[k] = dists[bestIndex];
+                               dists[bestIndex] = tf;
+                       }
+               }
+               bestIndex = -1;
+               // find the best change with an acceptable horizontal change
+               for(i = 0; i < totweight; i++) {
+                       if(fabs(changes[i][0]) > fabs(changes[i][1]*2.0f)) {
+                               bestIndex = i;
+                               break;
+                       }
+               }
+               if(bestIndex != -1) {
+                       wasChange = TRUE;
+                       // it is a good place to stop if it tries to move the opposite direction
+                       // (relative to the plane) of last time
+                       if(lastIndex != -1) {
+                               if(wasUp != upDown[bestIndex]) {
+                                       wasChange = FALSE;
+                               }
+                       }
+                       lastIndex = bestIndex;
+                       wasUp = upDown[bestIndex];
+                       dw = (dvert->dw+dwIndices[bestIndex]);
+                       oldw = dw->weight;
+                       if(upDown[bestIndex]) {
+                               dw->weight *= 1+cp;
+                       } else {
+                               dw->weight /= 1+cp;
+                       }
+                       if(dw->weight > 1) {
+                               dw->weight = 1;
+                       }
+                       if(oldw == dw->weight) {
+                               wasChange = FALSE;
+                       }
+                       if(dm) {
+                               dm_deform_clear(dm, ob); dm = NULL;
+                       }
+               }
+       }while(wasChange && (distToStart-distToBe)/fabs(distToStart-distToBe) == (dists[bestIndex]-distToBe)/fabs(dists[bestIndex]-distToBe));
+       MEM_freeN(upDown);
+       MEM_freeN(changes);
+       MEM_freeN(dists);
+       MEM_freeN(dwIndices);
+}
+
+/* this is used to try to smooth a surface by only adjusting the nonzero weights of a vertex 
+but it could be used to raise or lower an existing 'bump.' */
+static void vgroup_fix(Scene *scene, Object *ob, float distToBe, float strength, float cp)
+{
+       int i;
+
+       Mesh *me = ob->data;
+       MVert *mvert = me->mvert;
+       const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
+       int *verts = NULL;
+       for(i = 0; i < me->totvert && mvert; i++, mvert++) {
+               
+               if(use_vert_sel && (mvert->flag & SELECT)) {
+                       
+                       int count=0;
+                       if((verts = getSurroundingVerts(me, i, &count))) {
+                               MVert m;
+                               MVert *p = MEM_callocN(sizeof(MVert)*(count), "deformedPoints");
+                               int k;
+
+                               DerivedMesh *dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
+                               for(k = 0; k < count; k++) {
+                                       dm->getVert(dm, verts[k], &m);
+                                       p[k] = m;
+                               }
+                               
+                               if(count >= 3) {
+                                       float d /*, dist */ /* UNUSED */, mag;
+                                       float coord[3] = {0};
+                                       float norm[3] = {0};
+                                       getSingleCoordinate(p, count, coord);
+                                       dm->getVert(dm, i, &m);
+                                       norm[0] = m.co[0]-coord[0];
+                                       norm[1] = m.co[1]-coord[1];
+                                       norm[2] = m.co[2]-coord[2];
+                                       mag = sqrt(norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2]);
+                                       if(mag) {// zeros fix
+                                               mul_v3_fl(norm, 1.0f/mag);
+                                               
+                                               d = -norm[0]*coord[0] -norm[1]*coord[1] -norm[2]*coord[2];
+                                               /* dist = (norm[0]*m.co[0] + norm[1]*m.co[1] + norm[2]*m.co[2] + d); */ /* UNUSED */
+                                               moveCloserToDistanceFromPlane(scene, ob, me, i, norm, coord, d, distToBe, strength, cp);
+                                       }
+                               }
+
+                               MEM_freeN(verts);
+                               MEM_freeN(p);
+                       }
+               }
+       }
+}
+
 static void vgroup_levels(Object *ob, float offset, float gain)
 {
        bDeformGroup *dg;
@@ -743,6 +1154,10 @@ static void vgroup_levels(Object *ob, float offset, float gain)
        MDeformVert *dvert, **dvert_array=NULL;
        int i, def_nr, dvert_tot=0;
        
+       Mesh *me = ob->data;
+       MVert *mvert = me->mvert;
+       const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
+
        ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
        
        dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
@@ -751,6 +1166,11 @@ static void vgroup_levels(Object *ob, float offset, float gain)
                def_nr= ob->actdef-1;
                
                for(i = 0; i < dvert_tot; i++) {
+                       
+                       if(use_vert_sel && !(mvert[i].flag & SELECT)) {
+                               continue;
+                       }
+
                        dvert = dvert_array[i];
                        dw = defvert_find_index(dvert, def_nr);
                        if(dw) {
@@ -772,6 +1192,11 @@ static void vgroup_normalize_all(Object *ob, int lock_active)
        int i, dvert_tot=0;
        float tot_weight;
 
+       
+       Mesh *me = ob->data;
+       MVert *mvert = me->mvert;
+       const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
+
        ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
 
        if(dvert_array) {
@@ -781,6 +1206,10 @@ static void vgroup_normalize_all(Object *ob, int lock_active)
                        for(i = 0; i < dvert_tot; i++) {
                                float lock_iweight= 1.0f;
                                int j;
+                               
+                               if(use_vert_sel && !(mvert[i].flag & SELECT)) {
+                                       continue;
+                               }
 
                                tot_weight= 0.0f;
                                dw_act= NULL;
@@ -821,6 +1250,11 @@ static void vgroup_normalize_all(Object *ob, int lock_active)
                else {
                        for(i = 0; i < dvert_tot; i++) {
                                int j;
+                               
+                               if(use_vert_sel && !(mvert[i].flag & SELECT)) {
+                                       continue;
+                               }
+
                                tot_weight= 0.0f;
                                dvert = dvert_array[i];
 
@@ -848,12 +1282,45 @@ static void vgroup_normalize_all(Object *ob, int lock_active)
 }
 
 
+static void vgroup_lock_all(Object *ob, int action)
+{
+       bDeformGroup *dg;
+
+       if(action == SEL_TOGGLE) {
+               action= SEL_SELECT;
+               for(dg= ob->defbase.first; dg; dg= dg->next) {
+                       if(dg->flag & DG_LOCK_WEIGHT) {
+                               action= SEL_DESELECT;
+                               break;
+                       }
+               }
+       }
+
+       for(dg= ob->defbase.first; dg; dg= dg->next) {
+               switch(action) {
+                       case SEL_SELECT:
+                               dg->flag |= DG_LOCK_WEIGHT;
+                               break;
+                       case SEL_DESELECT:
+                               dg->flag &= ~DG_LOCK_WEIGHT;
+                               break;
+                       case SEL_INVERT:
+                               dg->flag ^= DG_LOCK_WEIGHT;
+                               break;
+               }
+       }
+}
+
 static void vgroup_invert(Object *ob, int auto_assign, int auto_remove)
 {
        bDeformGroup *dg;
        MDeformWeight *dw;
        MDeformVert *dvert, **dvert_array=NULL;
        int i, def_nr, dvert_tot=0;
+       
+       Mesh *me = ob->data;
+       MVert *mvert = me->mvert;
+       const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
 
        ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
 
@@ -864,6 +1331,10 @@ static void vgroup_invert(Object *ob, int auto_assign, int auto_remove)
 
 
                for(i = 0; i < dvert_tot; i++) {
+                       
+                       if(use_vert_sel && !(mvert[i].flag & SELECT)) {
+                               continue;
+                       }
                        dvert = dvert_array[i];
 
                        if(auto_assign) {
@@ -976,6 +1447,10 @@ static void vgroup_clean(Object *ob, float eul, int keep_single)
        MDeformWeight *dw;
        MDeformVert *dvert, **dvert_array=NULL;
        int i, def_nr, dvert_tot=0;
+       
+       Mesh *me = ob->data;
+       MVert *mvert = me->mvert;
+       const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
 
        ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
 
@@ -985,6 +1460,10 @@ static void vgroup_clean(Object *ob, float eul, int keep_single)
                def_nr= ob->actdef-1;
 
                for(i = 0; i < dvert_tot; i++) {
+                       
+                       if(use_vert_sel && !(mvert[i].flag & SELECT)) {
+                               continue;
+                       }
                        dvert = dvert_array[i];
 
                        dw= defvert_find_index(dvert, def_nr);
@@ -1006,12 +1485,21 @@ static void vgroup_clean_all(Object *ob, float eul, int keep_single)
        MDeformWeight *dw;
        MDeformVert *dvert, **dvert_array=NULL;
        int i, dvert_tot=0;
+       
+       Mesh *me = ob->data;
+       MVert *mvert = me->mvert;
+       const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
 
        ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
 
        if(dvert_array) {
                for(i = 0; i < dvert_tot; i++) {
                        int j;
+                       
+                       if(use_vert_sel && !(mvert[i].flag & SELECT)) {
+                               continue;
+                       }
+
                        dvert = dvert_array[i];
                        j= dvert->totweight;
 
@@ -1832,6 +2320,82 @@ void OBJECT_OT_vertex_group_normalize_all(wmOperatorType *ot)
        RNA_def_boolean(ot->srna, "lock_active", TRUE, "Lock Active", "Keep the values of the active group while normalizing others.");
 }
 
+static int vertex_group_fix_exec(bContext *C, wmOperator *op)
+{
+       Object *ob= CTX_data_active_object(C);
+       Scene *scene= CTX_data_scene(C);
+       
+       float distToBe= RNA_float_get(op->ptr, "dist");
+       float strength= RNA_float_get(op->ptr, "strength");
+       float cp= RNA_float_get(op->ptr, "accuracy");
+       ModifierData *md= ob->modifiers.first;
+
+       while(md) {
+               if(md->type == eModifierType_Mirror && (md->mode&eModifierMode_Realtime)) {
+                       break;
+               }
+               md = md->next;
+       }
+       
+       if(md && md->type == eModifierType_Mirror) {
+               BKE_report(op->reports, RPT_ERROR_INVALID_CONTEXT, "This operator does not support an active mirror modifier");
+               return OPERATOR_CANCELLED;
+       }
+       vgroup_fix(scene, ob, distToBe, strength, cp);
+       
+       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_fix(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Fix Vertex Group Deform";
+       ot->idname= "OBJECT_OT_vertex_group_fix";
+       ot->description= "Modify the position of selected vertices by changing only their respective groups' weights (this tool may be slow for many vertices).";
+       
+       /* api callbacks */
+       ot->poll= vertex_group_poll;
+       ot->exec= vertex_group_fix_exec;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       RNA_def_float(ot->srna, "dist", 0.0f, -FLT_MAX, FLT_MAX, "Distance", "The distance to move to.", -10.0f, 10.0f);        
+       RNA_def_float(ot->srna, "strength", 1.f, -2.0f, FLT_MAX, "Strength", "The distance moved can be changed by this multiplier.", -2.0f, 2.0f);
+       RNA_def_float(ot->srna, "accuracy", 1.0f, 0.05f, FLT_MAX, "Change Sensitivity", "Changes the amount weights are altered with each iteration: lower values are slower.", 0.05f, 1.f);
+}
+
+
+static int vertex_group_lock_exec(bContext *C, wmOperator *op)
+{
+       Object *ob= CTX_data_active_object(C);
+
+       int action = RNA_enum_get(op->ptr, "action");
+
+       vgroup_lock_all(ob, action);
+
+       return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_vertex_group_lock(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Change the Lock On Vertex Groups";
+       ot->idname= "OBJECT_OT_vertex_group_lock";
+
+       /* api callbacks */
+       ot->poll= vertex_group_poll;
+       ot->exec= vertex_group_lock_exec;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       WM_operator_properties_select_all(ot);
+}
+
 static int vertex_group_invert_exec(bContext *C, wmOperator *op)
 {
        Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
index 784c35ca523263703290080fa04f899418a39ad8..3b656338fd40edd68819a4087be0f5e845abb2d8 100644 (file)
@@ -5409,6 +5409,15 @@ int facemask_paint_poll(bContext *C)
        return paint_facesel_test(CTX_data_active_object(C));
 }
 
+int vert_paint_poll(bContext *C)
+{
+       return paint_vertsel_test(CTX_data_active_object(C));
+}
+
+int mask_paint_poll(bContext *C)
+{
+       return paint_facesel_test(CTX_data_active_object(C)) || paint_vertsel_test(CTX_data_active_object(C));
+}
 /* use project paint to re-apply an image */
 static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
 {
index 5a0ee19d6c935d1588d70d6e36be5bbe94b2fab7..f671b7b171303896a242d8f233ab1629fd2beac6 100644 (file)
@@ -122,6 +122,11 @@ void PAINT_OT_face_select_inverse(struct wmOperatorType *ot);
 void PAINT_OT_face_select_hide(struct wmOperatorType *ot);
 void PAINT_OT_face_select_reveal(struct wmOperatorType *ot);
 
+void PAINT_OT_vert_select_all(struct wmOperatorType *ot);
+void PAINT_OT_vert_select_inverse(struct wmOperatorType *ot);
+int vert_paint_poll(struct bContext *C);
+int mask_paint_poll(struct bContext *C);
+
 int facemask_paint_poll(struct bContext *C);
 
 /* stroke operator */
index 69af50415cc283a453485888f7d5047193cd0523..287d204115c763fc714c707a67038cf7e9eb398b 100644 (file)
@@ -373,6 +373,10 @@ void ED_operatortypes_paint(void)
        WM_operatortype_append(PAINT_OT_weight_sample);
        WM_operatortype_append(PAINT_OT_weight_sample_group);
 
+       /* vertex selection */
+       WM_operatortype_append(PAINT_OT_vert_select_all);
+       WM_operatortype_append(PAINT_OT_vert_select_inverse);
+
        /* vertex */
        WM_operatortype_append(PAINT_OT_vertex_paint_toggle);
        WM_operatortype_append(PAINT_OT_vertex_paint);
@@ -607,6 +611,17 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
 
        WM_keymap_verify_item(keymap, "PAINT_OT_weight_from_bones", WKEY, KM_PRESS, 0, 0);
 
+       
+       /*Weight paint's Vertex Selection Mode */
+       keymap= WM_keymap_find(keyconf, "Weight Paint Vertex Selection", 0, 0);
+       keymap->poll= vert_paint_poll;
+       WM_keymap_add_item(keymap, "PAINT_OT_vert_select_all", AKEY, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "PAINT_OT_vert_select_inverse", IKEY, KM_PRESS, KM_CTRL, 0);
+       WM_keymap_add_item(keymap, "VIEW3D_OT_select_border", BKEY, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "VIEW3D_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
+       RNA_boolean_set(WM_keymap_add_item(keymap, "VIEW3D_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT|KM_CTRL, 0)->ptr, "deselect", 1);
+       WM_keymap_add_item(keymap, "VIEW3D_OT_select_circle", CKEY, KM_PRESS, 0, 0);
+
        /* Image/Texture Paint mode */
        keymap= WM_keymap_find(keyconf, "Image Paint", 0, 0);
        keymap->poll= image_texture_paint_poll;
index e088f59a1d20d9983d1565475279576f5ae15a04..d03be2c3a56249b8dbeea2bbfb7b02d1d9f743de 100644 (file)
@@ -387,6 +387,49 @@ void PAINT_OT_face_select_all(wmOperatorType *ot)
        WM_operator_properties_select_all(ot);
 }
 
+
+static int vert_select_all_exec(bContext *C, wmOperator *op)
+{
+       Object *ob= CTX_data_active_object(C);
+       paintvert_deselect_all_visible(ob, RNA_enum_get(op->ptr, "action"), TRUE);
+       ED_region_tag_redraw(CTX_wm_region(C));
+       return OPERATOR_FINISHED;
+}
+
+
+void PAINT_OT_vert_select_all(wmOperatorType *ot)
+{
+       ot->name= "Vertex Selection";
+       ot->description= "Change selection for all vertices";
+       ot->idname= "PAINT_OT_vert_select_all";
+
+       ot->exec= vert_select_all_exec;
+       ot->poll= vert_paint_poll;
+
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       WM_operator_properties_select_all(ot);
+}
+
+static int vert_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       Object *ob= CTX_data_active_object(C);
+       paintvert_deselect_all_visible(ob, SEL_INVERT, TRUE);
+       ED_region_tag_redraw(CTX_wm_region(C));
+       return OPERATOR_FINISHED;
+}
+
+void PAINT_OT_vert_select_inverse(wmOperatorType *ot)
+{
+       ot->name= "Vertex Select Invert";
+       ot->description= "Invert selection of vertices";
+       ot->idname= "PAINT_OT_vert_select_inverse";
+
+       ot->exec= vert_select_inverse_exec;
+       ot->poll= vert_paint_poll;
+
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
 static int face_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
 {
        Object *ob= CTX_data_active_object(C);
index 3da19ba7346ebe37c74946fe846bdf20c99e8133..6cda5e07118f0227c1ea5719af4b3dcb1a2cb37e 100644 (file)
@@ -64,6 +64,7 @@
 #include "RNA_enum_types.h"
 
 #include "BKE_DerivedMesh.h"
+#include "BKE_armature.h"
 #include "BKE_action.h"
 #include "BKE_brush.h"
 #include "BKE_context.h"
@@ -399,10 +400,14 @@ void wpaint_fill(VPaint *wp, Object *ob, float paintweight)
        int vgroup_mirror= -1;
        int selected;
        
+       int use_vert_sel;
+
        me= ob->data;
        if(me==NULL || me->totface==0 || me->dvert==NULL || !me->mface) return;
        
        selected= (me->editflag & ME_EDIT_PAINT_MASK);
+       
+       use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
 
        indexar= get_indexarray(me);
 
@@ -437,7 +442,12 @@ void wpaint_fill(VPaint *wp, Object *ob, float paintweight)
                        faceverts[2]= mface->v3;
                        faceverts[3]= mface->v4;
                        for (i=0; i<3 || faceverts[i]; i++) {
-                               if(!((me->dvert+faceverts[i])->flag)) {
+                               if(!me->dvert[faceverts[i]].flag) {
+
+                                       if(use_vert_sel && !(me->mvert[faceverts[i]].flag & SELECT)) {
+                                               continue;
+                                       }
+
                                        dw= defvert_verify_index(me->dvert+faceverts[i], vgroup);
                                        if(dw) {
                                                uw= defvert_verify_index(wp->wpaint_prev+faceverts[i], vgroup);
@@ -792,7 +802,7 @@ static float calc_vp_alpha_dl(VPaint *vp, ViewContext *vc, float vpimat[][3], fl
        return alpha;
 }
 
-static void wpaint_blend(VPaint *wp, MDeformWeight *dw, MDeformWeight *uw, float alpha, float paintval, int flip)
+static void wpaint_blend(VPaint *wp, MDeformWeight *dw, MDeformWeight *uw, float alpha, float paintval, int flip, int multipaint)
 {
        Brush *brush = paint_brush(&wp->paint);
        int tool = brush->vertexpaint_tool;
@@ -830,7 +840,10 @@ static void wpaint_blend(VPaint *wp, MDeformWeight *dw, MDeformWeight *uw, float
                if (dw->weight > paintval)
                        dw->weight = paintval*alpha + dw->weight*(1.0f-alpha);
        }
-       CLAMP(dw->weight, 0.0f, 1.0f);
+       /*  delay clamping until the end so multi-paint can function when the active group is at the limits */
+       if(multipaint == FALSE) {
+               CLAMP(dw->weight, 0.0f, 1.0f);
+       }
        
        /* if no spray, clip result with orig weight & orig alpha */
        if((wp->flag & VP_SPRAY)==0) {
@@ -857,15 +870,17 @@ static void wpaint_blend(VPaint *wp, MDeformWeight *dw, MDeformWeight *uw, float
                        else
                                testw = uw->weight;
                }
-               CLAMP(testw, 0.0f, 1.0f);
-               
-               if( testw<uw->weight ) {
-                       if(dw->weight < testw) dw->weight= testw;
-                       else if(dw->weight > uw->weight) dw->weight= uw->weight;
-               }
-               else {
-                       if(dw->weight > testw) dw->weight= testw;
-                       else if(dw->weight < uw->weight) dw->weight= uw->weight;
+
+               if(multipaint == FALSE) {
+                       CLAMP(testw, 0.0f, 1.0f);
+                       if( testw<uw->weight ) {
+                               if(dw->weight < testw) dw->weight= testw;
+                               else if(dw->weight > uw->weight) dw->weight= uw->weight;
+                       }
+                       else {
+                               if(dw->weight > testw) dw->weight= testw;
+                               else if(dw->weight < uw->weight) dw->weight= uw->weight;
+                       }
                }
        }
        
@@ -1062,6 +1077,7 @@ void PAINT_OT_weight_sample_group(wmOperatorType *ot)
 }
 
 
+#if 0 /* UNUSED */
 static void do_weight_paint_auto_normalize(MDeformVert *dvert, 
                                           int paint_nr, char *map)
 {
@@ -1096,15 +1112,456 @@ static void do_weight_paint_auto_normalize(MDeformVert *dvert,
                }
        }
 }
+#endif
+
+/* the active group should be involved in auto normalize */
+static void do_weight_paint_auto_normalize_all_groups(MDeformVert *dvert, char *map)
+{
+//     MDeformWeight *dw = dvert->dw;
+       float sum=0.0f, fac=0.0f;
+       int i, tot=0;
+
+       if (!map)
+               return;
+
+       for (i=0; i<dvert->totweight; i++) {
+               if (map[dvert->dw[i].def_nr]) {
+                       tot += 1;
+                       sum += dvert->dw[i].weight;
+               }
+       }
+       
+       if (!tot || sum == 1.0f)
+               return;
+
+       fac = sum;
+       fac = fac==0.0f ? 1.0f : 1.0f / fac;
+
+       for (i=0; i<dvert->totweight; i++) {
+               if (map[dvert->dw[i].def_nr]) {
+                       dvert->dw[i].weight *= fac;
+               }
+       }
+}
+
+/*
+See if the current deform vertex has a locked group
+*/
+static char has_locked_group(MDeformVert *dvert, const char *lock_flags)
+{
+       int i;
+       for(i = 0; i < dvert->totweight; i++) {
+               if(lock_flags[dvert->dw[i].def_nr] && dvert->dw[i].weight > 0.0f) {
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+/* 
+ * gen_lck_flags gets the status of "flag" for each bDeformGroup
+ *in ob->defbase and returns an array containing them
+ */
+static char *gen_lock_flags(Object* ob, int defbase_tot)
+{
+       char is_locked = FALSE;
+       int i;
+       //int defbase_tot = BLI_countlist(&ob->defbase);
+       char *lock_flags = MEM_mallocN(defbase_tot*sizeof(char), "defflags");
+       bDeformGroup *defgroup;
+
+       for(i = 0, defgroup = ob->defbase.first; i < defbase_tot && defgroup; defgroup = defgroup->next, i++) {
+               lock_flags[i] = ((defgroup->flag & DG_LOCK_WEIGHT) != 0);
+               is_locked |= lock_flags[i];
+       }
+       if(is_locked){
+               return lock_flags;
+       }
+       // don't forget to free it if it is unneeded
+       MEM_freeN(lock_flags);
+       return NULL;
+}
+
+static int has_locked_group_selected(int defbase_tot, char *defbase_sel, char *lock_flags) {
+       int i;
+       for(i = 0; i < defbase_tot; i++) {
+               if(defbase_sel[i] && lock_flags[i]) {
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+
+#if 0 /* UNUSED */
+static int has_unselected_unlocked_bone_group(int defbase_tot, char *defbase_sel, int selected, char *lock_flags, char *vgroup_validmap) {
+       int i;
+       if(defbase_tot == selected) {
+               return FALSE;
+       }
+       for(i = 0; i < defbase_tot; i++) {
+               if(vgroup_validmap[i] && !defbase_sel[i] && !lock_flags[i]) {
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+#endif
+
+
+static void multipaint_selection(MDeformVert *dvert, float change, char *defbase_sel, int defbase_tot) {
+       int i;
+       MDeformWeight *dw;
+       float val;
+       // make sure they are all at most 1 after the change
+       for(i = 0; i < defbase_tot; i++) {
+               if(defbase_sel[i]) {
+                       dw = defvert_find_index(dvert, i);
+                       if(dw && dw->weight) {
+                               val = dw->weight * change;
+                               if(val > 1) {
+                                       /*  TODO: when the change is reduced, you need to recheck the earlier values to make sure they are not 0 (precision error) */
+                                       change = 1.0f/dw->weight;
+                               }
+                               // the value should never reach zero while multi-painting if it was nonzero beforehand
+                               if(val <= 0) {
+                                       return;
+                               }
+                       }
+               }
+       }
+       // apply the valid change
+       for(i = 0; i < defbase_tot; i++) {
+               if(defbase_sel[i]) {
+                       dw = defvert_find_index(dvert, i);
+                       if(dw && dw->weight) {
+                               dw->weight = dw->weight * change;
+                       }
+               }
+       }
+}
+
+// move all change onto valid, unchanged groups.  If there is change left over, then return it.
+// assumes there are valid groups to shift weight onto
+static float redistribute_change(MDeformVert *ndv, char *change_status, int changeme, int changeto, const char *vgroup_validmap, float totchange, float total_valid) {
+       float was_change;
+       float change;
+       float oldval;
+       MDeformWeight *ndw;
+       int i;
+       do {
+               // assume there is no change until you see one
+               was_change = FALSE;
+               // change each group by the same amount each time
+               change = totchange/total_valid;
+               for(i = 0; i < ndv->totweight && total_valid && totchange; i++) {
+                       ndw = (ndv->dw+i);
+                       // change only the groups with a valid status
+                       if(change_status[ndw->def_nr] == changeme) {
+                               oldval = ndw->weight;
+                               // if auto normalize is active, don't worry about upper bounds
+                               if(!vgroup_validmap && ndw->weight + change > 1) {
+                                       totchange -= 1-ndw->weight;
+                                       ndw->weight = 1;
+                                       // stop the changes to this group
+                                       change_status[ndw->def_nr] = changeto;
+                                       total_valid--;
+                               } else if(ndw->weight + change < 0) { // check the lower bound
+                                       totchange -= ndw->weight;
+                                       ndw->weight = 0;
+                                       change_status[ndw->def_nr] = changeto;
+                                       total_valid--;
+                               } else {// a perfectly valid change occurred to ndw->weight
+                                       totchange -= change;
+                                       ndw->weight += change;
+                               }
+                               // see if there was a change
+                               if(oldval != ndw->weight) {
+                                       was_change = TRUE;
+                               }
+                       }
+               }
+       // don't go again if there was no change, if there is no valid group, or there is no change left
+       }while(was_change && total_valid && totchange);
+       // left overs
+       return totchange;
+}
+
+// observe the changes made to the weights of groups.
+// make sure all locked groups on the vertex have the same deformation
+// by moving the changes made to groups onto other unlocked groups
+static void enforce_locks(MDeformVert *odv, MDeformVert *ndv, int defbase_tot,
+                          const char *lock_flags, const char *vgroup_validmap)
+{
+       float totchange = 0.0f;
+       float totchange_allowed = 0.0f;
+       float left_over;
+
+       int total_valid = 0;
+       int total_changed = 0;
+       int i;
+       MDeformWeight *ndw;
+       MDeformWeight *odw;
+       MDeformWeight *ndw2;
+       MDeformWeight *odw2;
+       int designatedw = -1;
+       int designatedw_changed = FALSE;
+       float storedw;
+       char *change_status;
+       char new_weight_has_zero = FALSE;
+
+       if(!lock_flags || !has_locked_group(ndv, lock_flags)) {
+               return;
+       }
+       // record if a group was changed, unlocked and not changed, or locked
+       change_status = MEM_callocN(sizeof(char)*defbase_tot, "unlocked_unchanged");
+
+       for(i = 0; i < defbase_tot; i++) {
+               ndw = defvert_find_index(ndv, i);
+               odw = defvert_find_index(odv, i);
+               // the weights are zero, so we can assume a lot
+               if(!ndw || !odw) {
+                       if (!lock_flags[i] && vgroup_validmap[i]){
+                               defvert_verify_index(odv, i);
+                               defvert_verify_index(ndv, i);
+                               total_valid++;
+                               change_status[i] = 1; // can be altered while redistributing
+                       }
+                       continue;
+               }
+               // locked groups should not be changed
+               if(lock_flags[i]) {
+                       ndw->weight = odw->weight;
+               }
+               else if(ndw->weight != odw->weight) { // changed groups are handled here
+                       totchange += ndw->weight - odw->weight;
+                       change_status[i] = 2; // was altered already
+                       total_changed++;
+                       if(ndw->weight == 0) {
+                               new_weight_has_zero = TRUE;
+                       }
+                       else if(designatedw == -1){
+                               designatedw = i;
+                       }
+               } // unchanged, unlocked bone groups are handled here
+               else if (vgroup_validmap[i]){
+                       totchange_allowed += ndw->weight;
+                       total_valid++;
+                       change_status[i] = 1; // can be altered while redistributing
+               }
+       }
+       // if there was any change, redistribute it
+       if(total_changed) {
+               // auto normalize will allow weights to temporarily go above 1 in redistribution
+               if(vgroup_validmap && total_changed < 0 && total_valid) {
+                       totchange_allowed = total_valid;
+               }
+               // there needs to be change allowed, or you should not bother
+               if(totchange_allowed) {
+                       // the way you modify the unlocked+unchanged groups is different depending
+                       // on whether or not you are painting the weight(s) up or down
+                       if(totchange < 0) {
+                               totchange_allowed = total_valid - totchange_allowed;
+                       }
+                       else {
+                               totchange_allowed *= -1;
+                       }
+                       left_over = 0;
+                       if(fabsf(totchange_allowed) < fabsf(totchange)) {
+                               // this amount goes back onto the changed, unlocked weights
+                               left_over = fabsf(fabsf(totchange) - fabsf(totchange_allowed));
+                               if(totchange > 0) {
+                                       left_over *= -1;
+                               }
+                       }
+                       else {
+                               // all of the change will be permitted
+                               totchange_allowed = -totchange;
+                       }
+                       // move the weight evenly between the allowed groups, move excess back onto the used groups based on the change
+                       totchange_allowed = redistribute_change(ndv, change_status, 1, -1, vgroup_validmap, totchange_allowed, total_valid);
+                       left_over += totchange_allowed;
+                       if(left_over) {
+                               // more than one nonzero weights were changed with the same ratio, so keep them changed that way!
+                               if(total_changed > 1 && !new_weight_has_zero && designatedw >= 0) {
+                                       // this dw is special, it is used as a base to determine how to change the others
+                                       ndw = defvert_find_index(ndv, designatedw);
+                                       odw = defvert_find_index(odv, designatedw);
+                                       storedw = ndw->weight;
+                                       for(i = 0; i < ndv->totweight; i++) {
+                                               if(change_status[ndw->def_nr] == 2) {
+                                                       odw2 = (odv->dw+i);
+                                                       ndw2 = (ndv->dw+i);
+                                                       if(!designatedw_changed) {
+                                                               ndw->weight = (totchange_allowed + odw->weight + odw2->weight)/(1 + ndw2->weight/ndw->weight);
+                                                               designatedw_changed = TRUE;
+                                                       }
+                                                       ndw2->weight = ndw->weight * ndw2->weight / storedw;
+                                               }
+                                       }
+                               }
+                               // a weight was changed to zero, only one weight was changed, or designatedw is still -1
+                               // put weight back as evenly as possible
+                               else {
+                                       redistribute_change(ndv, change_status, 2, -2, vgroup_validmap, left_over, total_changed);
+                               }
+                       }
+               }
+               else {
+                       // reset the weights
+                       for(i = 0; i < ndv->totweight; i++) {
+                               ndv->dw[i].weight = odv->dw[i].weight;
+                       }
+               }
+       }
+
+       MEM_freeN(change_status);
+}
+
+// multi-paint's initial, potential change is computed here based on the user's stroke
+static float get_mp_change(MDeformVert *odv, char *defbase_sel, float brush_change) {
+       float selwsum = 0.0f;
+       int i;
+       MDeformWeight *dw;
+       for(i=0; i < odv->totweight; i++) {
+               if(defbase_sel[(dw= &odv->dw[i])->def_nr]) {
+                       selwsum += dw->weight;
+               }
+       }
+       if(selwsum && selwsum+brush_change > 0) {
+               return (selwsum+brush_change)/selwsum;
+       }
+       return 0.0f;
+}
+
+// change the weights back to the wv's weights
+// it assumes you already have the correct pointer index
+static void reset_to_prev(MDeformVert *wv, MDeformVert *dv) {
+       int i;
+       MDeformWeight *d;
+       MDeformWeight *w;
+       for(i = 0; i < dv->totweight; i++) {
+               d= &dv->dw[i];
+               w= defvert_find_index(wv, d->def_nr);
+               /* if there was no w when there is a d, then the old weight was 0 */
+               d->weight = w ? w->weight : 0.0f;
+       }
+}
+
+static void clamp_weights(MDeformVert *dvert) {
+       int i;
+       for (i = 0; i < dvert->totweight; i++) {
+               CLAMP((dvert->dw+i)->weight, 0.0f, 1.0f);
+       }
+}
+
+/* struct to avoid passing many args each call to do_weight_paint_vertex()
+ * this _could_ be made a part of the operators 'WPaintData' struct, or at
+ * least a member, but for now keep its own struct, initialized on every
+ * paint stroke update - campbell */
+typedef struct WeightPaintInfo {
+
+       int defbase_tot;
+
+       /* both must add up to 'defbase_tot' */
+       int defbase_tot_sel;
+       int defbase_tot_unsel;
+
+       int vgroup_mirror; /* mirror group or -1 */
+
+       char *lock_flags;  /* boolean array for locked bones,
+                                               * length of defbase_tot */
+       char *defbase_sel; /* boolean array for selected bones,
+                                               * length of defbase_tot */
+
+       char *vgroup_validmap; /* same as WeightPaintData.vgroup_validmap,
+                               * only added here for convenience */
+
+       char do_flip;
+       char do_multipaint;
+} WeightPaintInfo;
+
+/* fresh start to make multi-paint and locking modular */
+/* returns TRUE if it thinks you need to reset the weights due to
+ * normalizing while multi-painting */
+static int apply_mp_locks_normalize(Mesh *me, const WeightPaintInfo *wpi,
+                                    const int index,
+                                    MDeformWeight *dw, MDeformWeight *tdw,
+                                    float change, float oldChange,
+                                    float oldw, float neww)
+{
+       MDeformVert *dv= me->dvert+index;
+       MDeformVert dv_test= {NULL};
+
+       dv_test.dw= MEM_dupallocN(dv->dw);
+       dv_test.flag = dv->flag;
+       dv_test.totweight = dv->totweight;
+       /* do not multi-paint if a locked group is selected or the active group is locked
+        * !lock_flags[dw->def_nr] helps if nothing is selected, but active group is locked */
+       if((wpi->lock_flags == NULL) || (wpi->lock_flags[dw->def_nr] == FALSE && has_locked_group_selected(wpi->defbase_tot, wpi->defbase_sel, wpi->lock_flags) == FALSE)) {
+               if(wpi->do_multipaint && wpi->defbase_tot_sel > 1) {
+                       if(change && change!=1) {
+                               multipaint_selection(dv, change, wpi->defbase_sel, wpi->defbase_tot);
+                       }
+               }
+               else { /* this lets users paint normally, but don't let them paint locked groups */
+                       dw->weight = neww;
+               }
+       }
+       clamp_weights(dv);
+
+       enforce_locks(&dv_test, dv, wpi->defbase_tot, wpi->lock_flags, wpi->vgroup_validmap);
+
+       do_weight_paint_auto_normalize_all_groups(dv, wpi->vgroup_validmap);
+
+       if(oldChange && wpi->do_multipaint && wpi->defbase_tot_sel > 1) {
+               if(tdw->weight != oldw) {
+                       if(neww > oldw) {
+                               if(tdw->weight <= oldw) {
+                                       MEM_freeN(dv_test.dw);
+                                       return TRUE;
+                               }
+                       }
+                       else {
+                               if(tdw->weight >= oldw) {
+                                       MEM_freeN(dv_test.dw);
+                                       return TRUE;
+                               }
+                       }
+               }
+       }
+       MEM_freeN(dv_test.dw);
+       return FALSE;
+}
 
-static void do_weight_paint_vertex(VPaint *wp, Object *ob, int index, 
-                                  float alpha, float paintweight, int flip, 
-                                  int vgroup_mirror, char *validmap)
+/* within the current dvert index, get the dw that is selected and has a weight
+ * above 0, this helps multi-paint */
+static int get_first_selected_nonzero_weight(MDeformVert *dvert, char *defbase_sel) {
+       int i;
+       MDeformWeight *dw;
+       for(i=0; i< dvert->totweight; i++) {
+               dw = &dvert->dw[i];
+               if(defbase_sel[dw->def_nr] && dw->weight > 0) {
+                       return i;
+               }
+       }
+       return -1;
+}
+
+
+static char *wpaint_make_validmap(Object *ob);
+
+
+static void do_weight_paint_vertex( /* vars which remain the same for every vert */
+                                   VPaint *wp, Object *ob, const WeightPaintInfo *wpi,
+                                    /* vars which change on each stroke */
+                                   int index, float alpha, float paintweight
+                                   )
 {
        Mesh *me= ob->data;
+       
        MDeformWeight *dw, *uw;
        int vgroup= ob->actdef-1;
-       
+
        if(wp->flag & VP_ONLYVGROUP) {
                dw= defvert_find_index(me->dvert+index, vgroup);
                uw= defvert_find_index(wp->wpaint_prev+index, vgroup);
@@ -1115,22 +1572,115 @@ static void do_weight_paint_vertex(VPaint *wp, Object *ob, int index,
        }
        if(dw==NULL || uw==NULL)
                return;
-       
-       wpaint_blend(wp, dw, uw, alpha, paintweight, flip);
-       do_weight_paint_auto_normalize(me->dvert+index, vgroup, validmap);
 
-       if(me->editflag & ME_EDIT_MIRROR_X) {   /* x mirror painting */
-               int j= mesh_get_x_mirror_vert(ob, index);
-               if(j>=0) {
-                       /* copy, not paint again */
-                       if(vgroup_mirror != -1)
-                               uw= defvert_verify_index(me->dvert+j, vgroup_mirror);
-                       else
-                               uw= defvert_verify_index(me->dvert+j, vgroup);
-                               
-                       uw->weight= dw->weight;
+       /* TODO: De-duplicate the simple weight paint - jason */
+       /* ... or not, since its <10 SLOC - campbell */
+
+       /* If there are no locks or multipaint,
+        * then there is no need to run the more complicated checks */
+       if((wpi->do_multipaint == FALSE || wpi->defbase_tot_sel <= 1) && (wpi->lock_flags == NULL || has_locked_group(&me->dvert[index], wpi->lock_flags) == FALSE)) {
+               wpaint_blend(wp, dw, uw, alpha, paintweight, wpi->do_flip, FALSE);
+               do_weight_paint_auto_normalize_all_groups(me->dvert+index, wpi->vgroup_validmap);
+
+               if(me->editflag & ME_EDIT_MIRROR_X) {   /* x mirror painting */
+                       int j= mesh_get_x_mirror_vert(ob, index);
+                       if(j>=0) {
+                               /* copy, not paint again */
+                               uw= defvert_verify_index(me->dvert+j, (wpi->vgroup_mirror != -1) ? wpi->vgroup_mirror : vgroup);
+                                       
+                               uw->weight= dw->weight;
 
-                       do_weight_paint_auto_normalize(me->dvert+j, vgroup, validmap);
+                               do_weight_paint_auto_normalize_all_groups(me->dvert+j, wpi->vgroup_validmap);
+                       }
+               }
+       }
+       else {
+               /* use locks and/or multipaint */
+               float oldw;
+               float neww;
+               float testw=0;
+               float change = 0;
+               float oldChange = 0;
+               int i;
+               MDeformWeight *tdw = NULL, *tuw;
+               MDeformVert dv= {NULL};
+
+               oldw = dw->weight;
+               wpaint_blend(wp, dw, uw, alpha, paintweight, wpi->do_flip, wpi->do_multipaint && wpi->defbase_tot_sel >1);
+               neww = dw->weight;
+               dw->weight = oldw;
+               
+               // setup multi-paint
+               if(wpi->defbase_tot_sel > 1 && wpi->do_multipaint) {
+                       dv.dw= MEM_dupallocN((me->dvert+index)->dw);
+                       dv.flag = me->dvert[index].flag;
+                       dv.totweight = (me->dvert+index)->totweight;
+                       tdw = dw;
+                       tuw = uw;
+                       change = get_mp_change(wp->wpaint_prev+index, wpi->defbase_sel, neww - oldw);
+                       if(change) {
+                               if(!tdw->weight) {
+                                       i = get_first_selected_nonzero_weight(me->dvert+index, wpi->defbase_sel);
+                                       if(i>=0) {
+                                               tdw = &(me->dvert[index].dw[i]);
+                                               tuw = defvert_verify_index(wp->wpaint_prev+index, tdw->def_nr);
+                                       }
+                                       else {
+                                               change = 0;
+                                       }
+                               }
+                               if(change && tuw->weight && tuw->weight * change) {
+                                       if(tdw->weight != tuw->weight) {
+                                               oldChange = tdw->weight/tuw->weight;
+                                               testw = tuw->weight*change;
+                                               if( testw > tuw->weight ) {
+                                                       if(change > oldChange) {
+                                                               /* reset the weights and use the new change */
+                                                               reset_to_prev(wp->wpaint_prev+index, me->dvert+index);
+                                                       }
+                                                       else {
+                                                               /* the old change was more significant, so set
+                                                                * the change to 0 so that it will not do another multi-paint */
+                                                               change = 0;
+                                                       }
+                                               }
+                                               else {
+                                                       if(change < oldChange) {
+                                                               reset_to_prev(wp->wpaint_prev+index, me->dvert+index);
+                                                       }
+                                                       else {
+                                                               change = 0;
+                                                       }
+                                               }
+                                       }
+                               }
+                               else {
+                                       change = 0;
+                               }
+                       }
+               }
+               
+               if(apply_mp_locks_normalize(me, wpi, index, dw, tdw, change, oldChange, oldw, neww)) {
+                       reset_to_prev(&dv, me->dvert+index);
+                       change = 0;
+                       oldChange = 0;
+               }
+               if(dv.dw) {
+                       MEM_freeN(dv.dw);
+               }
+               /* dvert may have been altered greatly */
+               dw = defvert_find_index(me->dvert+index, vgroup);
+
+               if(me->editflag & ME_EDIT_MIRROR_X) {   /* x mirror painting */
+                       int j= mesh_get_x_mirror_vert(ob, index);
+                       if(j>=0) {
+                               /* copy, not paint again */
+                               uw= defvert_verify_index(me->dvert+j, (wpi->vgroup_mirror != -1) ? wpi->vgroup_mirror : vgroup);
+                               
+                               //uw->weight= dw->weight;
+                               
+                               apply_mp_locks_normalize(me, wpi, j, uw, tdw, change, oldChange, oldw, neww);
+                       }
                }
        }
 }
@@ -1233,10 +1783,7 @@ static char *wpaint_make_validmap(Object *ob)
 {
        bDeformGroup *dg;
        ModifierData *md;
-       char *validmap;
-       bPose *pose;
-       bPoseChannel *chan;
-       ArmatureModifierData *amd;
+       char *vgroup_validmap;
        GHash *gh = BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "wpaint_make_validmap gh");
        int i = 0, step1=1;
 
@@ -1248,7 +1795,7 @@ static char *wpaint_make_validmap(Object *ob)
        if (!i)
                return NULL;
 
-       validmap = MEM_callocN(i, "wpaint valid map");
+       vgroup_validmap= MEM_callocN(i, "wpaint valid map");
 
        /*now loop through the armature modifiers and identify deform bones*/
        for (md = ob->modifiers.first; md; md= !md->next && step1 ? (step1=0), modifiers_getVirtualModifierList(ob) : md->next) {
@@ -1257,10 +1804,11 @@ static char *wpaint_make_validmap(Object *ob)
 
                if (md->type == eModifierType_Armature) 
                {
-                       amd = (ArmatureModifierData*) md;
+                       ArmatureModifierData *amd= (ArmatureModifierData*) md;
 
                        if(amd->object && amd->object->pose) {
-                               pose = amd->object->pose;
+                               bPose *pose= amd->object->pose;
+                               bPoseChannel *chan;
                                
                                for (chan=pose->chanbase.first; chan; chan=chan->next) {
                                        if (chan->bone->flag & BONE_NO_DEFORM)
@@ -1278,13 +1826,13 @@ static char *wpaint_make_validmap(Object *ob)
        /*add all names to a hash table*/
        for (dg=ob->defbase.first, i=0; dg; dg=dg->next, i++) {
                if (BLI_ghash_lookup(gh, dg->name) != NULL) {
-                       validmap[i] = 1;
+                       vgroup_validmap[i] = TRUE;
                }
        }
 
        BLI_ghash_free(gh, NULL, NULL);
 
-       return validmap;
+       return vgroup_validmap;
 }
 
 static int wpaint_stroke_test_start(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
@@ -1318,7 +1866,7 @@ static int wpaint_stroke_test_start(bContext *C, wmOperator *op, wmEvent *UNUSED
        /*set up auto-normalize, and generate map for detecting which
          vgroups affect deform bones*/
        wpd->auto_normalize = ts->auto_normalize;
-       if (wpd->auto_normalize)
+       if (wpd->auto_normalize || ts->multipaint)
                wpd->vgroup_validmap = wpaint_make_validmap(ob);
        
        //      if(qual & LR_CTRLKEY) {
@@ -1385,10 +1933,14 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
        float mat[4][4];
        float paintweight;
        int *indexar;
-       int totindex, index, totw, flip;
+       int totindex, index, totw;
        float alpha;
        float mval[2], pressure;
-       
+       int use_vert_sel;
+
+       /* intentionally dont initialize as NULL, make sure we initialize all members below */
+       WeightPaintInfo wpi;
+
        /* cannot paint if there is no stroke data */
        if (wpd == NULL) {
                // XXX: force a redraw here, since even though we can't paint, 
@@ -1407,17 +1959,38 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
        /* load projection matrix */
        mul_m4_m4m4(mat, ob->obmat, vc->rv3d->persmat);
 
-       flip = RNA_boolean_get(itemptr, "pen_flip");
        pressure = RNA_float_get(itemptr, "pressure");
        RNA_float_get_array(itemptr, "mouse", mval);
        mval[0]-= vc->ar->winrct.xmin;
        mval[1]-= vc->ar->winrct.ymin;
-                       
+
+
+
+       /* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */
+       wpi.defbase_tot=        BLI_countlist(&ob->defbase);
+       wpi.defbase_sel=        MEM_mallocN(wpi.defbase_tot*sizeof(char), "wpi.defbase_sel");
+       wpi.defbase_tot_sel=    get_selected_defgroups(ob, wpi.defbase_sel, wpi.defbase_tot);
+       if(wpi.defbase_tot_sel == 0 && ob->actdef) wpi.defbase_tot_sel = 1;
+       wpi.defbase_tot_unsel=  wpi.defbase_tot - wpi.defbase_tot_sel;
+       wpi.vgroup_mirror=      wpd->vgroup_mirror;
+       wpi.lock_flags=         gen_lock_flags(ob, wpi.defbase_tot);
+       wpi.vgroup_validmap=    wpd->vgroup_validmap;
+       wpi.do_flip=            RNA_boolean_get(itemptr, "pen_flip");
+       wpi.do_multipaint=      (ts->multipaint != 0);
+       /* *** done setting up WeightPaintInfo *** */
+
+
+
        swap_m4m4(wpd->vc.rv3d->persmat, mat);
-                       
+
+       use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
+
        /* which faces are involved */
        if(wp->flag & VP_AREA) {
+               // Ugly hack, to avoid drawing vertex index when getting the face index buffer - campbell
+               me->editflag &= ~ME_EDIT_VERT_SEL;
                totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush_size(brush));
+               me->editflag |= use_vert_sel ? ME_EDIT_VERT_SEL : 0;
        }
        else {
                indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]);
@@ -1460,11 +2033,19 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
        for(index=0; index<totindex; index++) {
                if(indexar[index] && indexar[index]<=me->totface) {
                        MFace *mface= me->mface + (indexar[index]-1);
-                                       
-                       (me->dvert+mface->v1)->flag= 1;
-                       (me->dvert+mface->v2)->flag= 1;
-                       (me->dvert+mface->v3)->flag= 1;
-                       if(mface->v4) (me->dvert+mface->v4)->flag= 1;
+
+                       if(use_vert_sel) {
+                               me->dvert[mface->v1].flag = (me->mvert[mface->v1].flag & SELECT);
+                               me->dvert[mface->v2].flag = (me->mvert[mface->v2].flag & SELECT);
+                               me->dvert[mface->v3].flag = (me->mvert[mface->v3].flag & SELECT);
+                               if(mface->v4) me->dvert[mface->v4].flag = (me->mvert[mface->v4].flag & SELECT);
+                       }
+                       else {
+                               me->dvert[mface->v1].flag= 1;
+                               me->dvert[mface->v2].flag= 1;
+                               me->dvert[mface->v3].flag= 1;
+                               if(mface->v4) me->dvert[mface->v4].flag= 1;
+                       }
                                        
                        if(brush->vertexpaint_tool==VP_BLUR) {
                                MDeformWeight *dw, *(*dw_func)(MDeformVert *, const int);
@@ -1494,52 +2075,31 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
        for(index=0; index<totindex; index++) {
                                
                if(indexar[index] && indexar[index]<=me->totface) {
-                       MFace *mface= me->mface + (indexar[index]-1);
-                                       
-                       if((me->dvert+mface->v1)->flag) {
-                               alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v1, mval, pressure);
-                               if(alpha) {
-                                       do_weight_paint_vertex(wp, ob, mface->v1, 
-                                               alpha, paintweight, flip, wpd->vgroup_mirror, 
-                                               wpd->vgroup_validmap);
-                               }
-                               (me->dvert+mface->v1)->flag= 0;
-                       }
-                                       
-                       if((me->dvert+mface->v2)->flag) {
-                               alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v2, mval, pressure);
-                               if(alpha) {
-                                       do_weight_paint_vertex(wp, ob, mface->v2, 
-                                               alpha, paintweight, flip, wpd->vgroup_mirror, 
-                                               wpd->vgroup_validmap);
-                               }
-                               (me->dvert+mface->v2)->flag= 0;
-                       }
-                                       
-                       if((me->dvert+mface->v3)->flag) {
-                               alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v3, mval, pressure);
-                               if(alpha) {
-                                       do_weight_paint_vertex(wp, ob, mface->v3, 
-                                               alpha, paintweight, flip, wpd->vgroup_mirror, 
-                                               wpd->vgroup_validmap);
-                               }
-                               (me->dvert+mface->v3)->flag= 0;
-                       }
-                                       
-                       if((me->dvert+mface->v4)->flag) {
-                               if(mface->v4) {
-                                       alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v4, mval, pressure);
+                       MFace *mf= me->mface + (indexar[index]-1);
+                       unsigned int fidx= mf->v4 ? 3:2;;
+                       do {
+                               int vidx= *(&mf->v1 + fidx);
+
+                               if(me->dvert[vidx].flag) {
+                                       alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*vidx, mval, pressure);
                                        if(alpha) {
-                                               do_weight_paint_vertex(wp, ob, mface->v4, 
-                                                       alpha, paintweight, flip, wpd->vgroup_mirror,
-                                                       wpd->vgroup_validmap);
+                                               do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight);
                                        }
-                                       (me->dvert+mface->v4)->flag= 0;
+                                       me->dvert[vidx].flag= 0;
                                }
-                       }
+                       } while (fidx--);
                }
        }
-                       
+
+
+       /* *** free wpi members */
+       if(wpi.lock_flags) {
+               MEM_freeN(wpi.lock_flags);
+       }
+       MEM_freeN(wpi.defbase_sel);
+       /* *** dont freeing wpi members */
+
+
        swap_m4m4(vc->rv3d->persmat, mat);
                        
        DAG_id_tag_update(ob->data, 0);
@@ -1645,7 +2205,7 @@ void PAINT_OT_weight_set(wmOperatorType *ot)
 
        /* api callbacks */
        ot->exec= weight_paint_set_exec;
-       ot->poll= facemask_paint_poll;
+       ot->poll= mask_paint_poll; /* it was facemask_paint_poll */
 
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
index 6e02ecbd5a866fed660736117a8949ce4e32fc75..b8d33de2e372877f49c8a5c6a0003c511dbd2b4c 100644 (file)
@@ -523,7 +523,7 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl)
        if(ob->mode & OB_MODE_EDIT)
                return;
        else if(ob==OBACT)
-               if(paint_facesel_test(ob))
+               if(paint_facesel_test(ob) || paint_vertsel_test(ob))
                        return;
 
        ddm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
index 0e8e6cdfee1be4d934413781cab3a209d86630ba..ecdac083aed15d19408e0753e556f3ec0bc9d32a 100644 (file)
@@ -1740,6 +1740,31 @@ void mesh_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, EditVe
        dm->release(dm);
 }
 
+/*  draw callback */
+static void drawSelectedVertices__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
+{
+       MVert *mv = &((MVert *)userData)[index];
+
+       if(!(mv->flag & ME_HIDE)) {
+               const char sel= mv->flag & SELECT;
+
+               // TODO define selected color
+               if(sel) {
+                       glColor3f(1.0f, 1.0f, 0.0f);
+               }
+               else {
+                       glColor3f(0.0f, 0.0f, 0.0f);
+               }
+
+               glVertex3fv(co);
+       }
+}
+
+static void drawSelectedVertices(DerivedMesh *dm, Mesh *me) {
+       glBegin(GL_POINTS);
+       dm->foreachMappedVert(dm, drawSelectedVertices__mapFunc, me->mvert);
+       glEnd();
+}
 static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, float *v0co, float *v1co)
 {
        struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; } *data = userData;
@@ -2924,7 +2949,16 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
                        bglPolygonOffset(rv3d->dist, 0.0);
                }
        }
-
+       
+       if(paint_vertsel_test(ob)) {
+               
+               glColor3f(0.0f, 0.0f, 0.0f);
+               glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
+               
+               drawSelectedVertices(dm, ob->data);
+               
+               glPointSize(1.0f);
+       }
        dm->release(dm);
 }
 
@@ -6516,6 +6550,32 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
 
 /* ***************** BACKBUF SEL (BBS) ********* */
 
+static void bbs_obmode_mesh_verts__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
+{
+       struct {void* offset; MVert *mvert;} *data = userData;
+       MVert *mv = &data->mvert[index];
+       int offset = (intptr_t) data->offset;
+
+       if (!(mv->flag & ME_HIDE)) {
+               WM_set_framebuffer_index_color(offset+index);
+               bglVertex3fv(co);
+       }
+}
+
+static void bbs_obmode_mesh_verts(Object *ob, DerivedMesh *dm, int offset)
+{
+       struct {void* offset; struct MVert *mvert;} data;
+       Mesh *me = ob->data;
+       MVert *mvert = me->mvert;
+       data.mvert = mvert;
+       data.offset = (void*)(intptr_t) offset;
+       glPointSize( UI_GetThemeValuef(TH_VERTEX_SIZE) );
+       bglBegin(GL_POINTS);
+       dm->foreachMappedVert(dm, bbs_obmode_mesh_verts__mapFunc, &data);
+       bglEnd();
+       glPointSize(1.0);
+}
+
 static void bbs_mesh_verts__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
 {
        int offset = (intptr_t) userData;
@@ -6614,6 +6674,17 @@ static int bbs_mesh_solid_hide__setDrawOpts(void *userData, int index, int *UNUS
        }
 }
 
+// must have called WM_set_framebuffer_index_color beforehand
+static int bbs_mesh_solid_hide2__setDrawOpts(void *userData, int index, int *UNUSED(drawSmooth_r))
+{
+       Mesh *me = userData;
+
+       if (!(me->mface[index].flag & ME_HIDE)) {
+               return 1;
+       } else {
+               return 0;
+       }
+}
 static void bbs_mesh_solid(Scene *scene, Object *ob)
 {
        DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
@@ -6672,7 +6743,21 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
                        EM_free_index_arrays();
                }
                else {
-                       bbs_mesh_solid(scene, ob);
+                       Mesh *me= ob->data;
+                       if(me->editflag & ME_EDIT_VERT_SEL) {
+                               DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
+                               glColor3ub(0, 0, 0);
+
+                               dm->drawMappedFaces(dm, bbs_mesh_solid_hide2__setDrawOpts, me, 0, GPU_enable_material, NULL);
+
+                               
+                               bbs_obmode_mesh_verts(ob, dm, 1);
+                               em_vertoffs = me->totvert+1;
+                               dm->release(dm);
+                       }
+                       else {
+                               bbs_mesh_solid(scene, ob);
+                       }
                }
                break;
        case OB_CURVE:
index 6833dec2e4373813176debedee88ffcb55e3fdbc..c46b6b6d70bad632ef90118eb9201c2a466c8a4e 100644 (file)
@@ -371,6 +371,10 @@ static void view3d_main_area_init(wmWindowManager *wm, ARegion *ar)
        keymap= WM_keymap_find(wm->defaultconf, "Face Mask", 0, 0);
        WM_event_add_keymap_handler(&ar->handlers, keymap);
        
+       
+       keymap= WM_keymap_find(wm->defaultconf, "Weight Paint Vertex Selection", 0, 0);
+       WM_event_add_keymap_handler(&ar->handlers, keymap);
+
        /* pose is not modal, operator poll checks for this */
        keymap= WM_keymap_find(wm->defaultconf, "Pose", 0, 0);
        WM_event_add_keymap_handler(&ar->handlers, keymap);
index 78dcf6c9a5c265e39cab3b24eb1c9440fa236577..980e27ce116d0bcb733022df6020055dadec4199 100644 (file)
@@ -500,7 +500,15 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
                PointerRNA meshptr;
 
                RNA_pointer_create(&ob->id, &RNA_Mesh, ob->data, &meshptr);
-               uiItemR(layout, &meshptr, "use_paint_mask", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+               if(ob->mode & (OB_MODE_TEXTURE_PAINT|OB_MODE_VERTEX_PAINT)) {
+                       uiItemR(layout, &meshptr, "use_paint_mask", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+               }
+               else {
+                       
+                       row= uiLayoutRow(layout, 1);
+                       uiItemR(row, &meshptr, "use_paint_mask", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+                       uiItemR(row, &meshptr, "use_paint_mask_vertex", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+               }
        } else {
                const char *str_menu;
 
index 65914ead899de7a511965209277c422acab1d89c..8cdb03abf38bcf212a06318891a259d75a161e9d 100644 (file)
 #include "BLI_linklist.h"
 #include "BLI_utildefines.h"
 
+/* vertex box select */
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+#include "BKE_global.h"
+
 #include "BKE_context.h"
 #include "BKE_paint.h"
 #include "BKE_armature.h"
@@ -198,6 +203,24 @@ static void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select)
        }
 }
 
+
+/* object mode, EM_ prefix is confusing here, rename? */
+static void EM_backbuf_checkAndSelectVerts_obmode(Mesh *me, int select)
+{
+       MVert *mv = me->mvert;
+       int a;
+
+       if (mv) {
+               for(a=1; a<=me->totvert; a++, mv++) {
+                       if(EM_check_backbuf(a)) {
+                               if(!(mv->flag & ME_HIDE)) {
+                                       mv->flag = select?(mv->flag|SELECT):(mv->flag&~SELECT);
+                               }
+                       }
+               }
+       }
+}
+/* object mode, EM_ prefix is confusing here, rename? */
 static void EM_backbuf_checkAndSelectTFaces(Mesh *me, int select)
 {
        MFace *mface = me->mface;
@@ -231,7 +254,7 @@ static int view3d_selectable_data(bContext *C)
                        if (ob->mode & OB_MODE_SCULPT) {
                                return 0;
                        }
-                       if (ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT) && !paint_facesel_test(ob)) {
+                       if (ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT) && !paint_facesel_test(ob) && !paint_vertsel_test(ob)) {
                                return 0;
                        }
                }
@@ -727,6 +750,88 @@ static void do_lasso_select_meta(ViewContext *vc, int mcords[][2], short moves,
        }
 }
 
+int do_paintvert_box_select(ViewContext *vc, rcti *rect, int select, int extend)
+{
+       Mesh *me;
+       MVert *mvert;
+       struct ImBuf *ibuf;
+       unsigned int *rt;
+       int a, index;
+       char *selar;
+       int sx= rect->xmax-rect->xmin+1;
+       int sy= rect->ymax-rect->ymin+1;
+
+       me= vc->obact->data;
+
+       if(me==NULL || me->totvert==0 || sx*sy <= 0)
+               return OPERATOR_CANCELLED;
+
+       selar= MEM_callocN(me->totvert+1, "selar");
+
+       if (extend == 0 && select)
+               paintvert_deselect_all_visible(vc->obact, SEL_DESELECT, FALSE);
+
+       view3d_validate_backbuf(vc);
+
+       ibuf = IMB_allocImBuf(sx,sy,32,IB_rect);
+       rt = ibuf->rect;
+       glReadPixels(rect->xmin+vc->ar->winrct.xmin,  rect->ymin+vc->ar->winrct.ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE,  ibuf->rect);
+       if(ENDIAN_ORDER==B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
+
+       a= sx*sy;
+       while(a--) {
+               if(*rt) {
+                       index= WM_framebuffer_to_index(*rt);
+                       if(index<=me->totvert) selar[index]= 1;
+               }
+               rt++;
+       }
+
+       mvert= me->mvert;
+       for(a=1; a<=me->totvert; a++, mvert++) {
+               if(selar[a]) {
+                       if(mvert->flag & ME_HIDE);
+                       else {
+                               if(select) mvert->flag |= SELECT;
+                               else mvert->flag &= ~SELECT;
+                       }
+               }
+       }
+
+       IMB_freeImBuf(ibuf);
+       MEM_freeN(selar);
+
+#ifdef __APPLE__       
+       glReadBuffer(GL_BACK);
+#endif
+
+       paintvert_flush_flags(vc->obact);
+
+       return OPERATOR_FINISHED;
+}
+
+static void do_lasso_select_paintvert(ViewContext *vc, int mcords[][2], short moves, short extend, short select)
+{
+       Object *ob= vc->obact;
+       Mesh *me= ob?ob->data:NULL;
+       rcti rect;
+
+       if(me==NULL || me->totvert==0)
+               return;
+
+       if(extend==0 && select)
+               paintvert_deselect_all_visible(ob, SEL_DESELECT, FALSE); /* flush selection at the end */
+       em_vertoffs= me->totvert+1;     /* max index array */
+
+       lasso_select_boundbox(&rect, mcords, moves);
+       EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+
+       EM_backbuf_checkAndSelectVerts_obmode(me, select);
+
+       EM_free_backbuf();
+
+       paintvert_flush_flags(ob);
+}
 static void do_lasso_select_paintface(ViewContext *vc, int mcords[][2], short moves, short extend, short select)
 {
        Object *ob= vc->obact;
@@ -789,6 +894,8 @@ static void view3d_lasso_select(bContext *C, ViewContext *vc, int mcords[][2], s
        if(vc->obedit==NULL) { /* Object Mode */
                if(paint_facesel_test(ob))
                        do_lasso_select_paintface(vc, mcords, moves, extend, select);
+               else if(paint_vertsel_test(ob))
+                       do_lasso_select_paintvert(vc, mcords, moves, extend, select);
                else if(ob && ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT))
                        ;
                else if(ob && ob->mode & OB_MODE_PARTICLE_EDIT)
@@ -1798,6 +1905,9 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op)
                else if(vc.obact && paint_facesel_test(vc.obact)) {
                        ret= do_paintface_box_select(&vc, &rect, select, extend);
                }
+               else if(vc.obact && paint_vertsel_test(vc.obact)) {
+                       ret= do_paintvert_box_select(&vc, &rect, select, extend);
+               }
                else if(vc.obact && vc.obact->mode & OB_MODE_PARTICLE_EDIT) {
                        ret= PE_border_select(C, &rect, select, extend);
                }
@@ -1834,6 +1944,57 @@ void VIEW3D_OT_select_border(wmOperatorType *ot)
        WM_operator_properties_gesture_border(ot, TRUE);
 }
 
+/* much like facesel_face_pick()*/
+/* returns 0 if not found, otherwise 1 */
+static int vertsel_vert_pick(struct bContext *C, Mesh *me, const int mval[2], unsigned int *index, short rect)
+{
+       ViewContext vc;
+       view3d_set_viewcontext(C, &vc);
+
+       if (!me || me->totvert==0)
+               return 0;
+
+       if (rect) {
+               /* sample rect to increase changes of selecting, so that when clicking
+                  on an face in the backbuf, we can still select a vert */
+
+               int dist;
+               *index = view3d_sample_backbuf_rect(&vc, mval, 3, 1, me->totvert+1, &dist,0,NULL, NULL);
+       }
+       else {
+               /* sample only on the exact position */
+               *index = view3d_sample_backbuf(&vc, mval[0], mval[1]);
+       }
+
+       if ((*index)<=0 || (*index)>(unsigned int)me->totvert)
+               return 0;
+
+       (*index)--;
+       
+       return 1;
+}
+
+/* mouse selection in weight paint */
+/* gets called via generic mouse select operator */
+int mouse_wp_select(bContext *C, const int mval[2], short extend, Object *obact, Mesh* me)
+{
+       unsigned int index = 0;
+       MVert *mv;
+       if(vertsel_vert_pick(C, me, mval, &index, 1)) {
+               mv = me->mvert+index;
+               if(extend) {
+                       mv->flag ^= 1;
+               } else {
+                       paintvert_deselect_all_visible(obact, SEL_DESELECT, FALSE);
+                       mv->flag |= 1;
+               }
+               paintvert_flush_flags(obact);
+               WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obact->data);
+               return 1;
+       }
+       return 0;
+}
+
 /* ****** Mouse Select ****** */
 
 
@@ -1878,8 +2039,12 @@ static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
                return PE_mouse_particles(C, event->mval, extend);
        else if(obact && paint_facesel_test(obact))
                retval = paintface_mouse_select(C, obact, event->mval, extend);
-       else
+       
+       else if (paint_vertsel_test(obact)) {
+               retval = mouse_wp_select(C, event->mval, extend, obact, obact->data);
+       } else {
                retval = mouse_select(C, event->mval, extend, center, enumerate);
+       }
 
        /* passthrough allows tweaks
         * FINISHED to signal one operator worked
@@ -2004,6 +2169,24 @@ static void paint_facesel_circle_select(ViewContext *vc, int select, const int m
 }
 
 
+static void paint_vertsel_circle_select(ViewContext *vc, int select, const int mval[2], float rad)
+{
+       Object *ob= vc->obact;
+       Mesh *me = ob?ob->data:NULL;
+       int bbsel;
+       /* struct {ViewContext *vc; short select; int mval[2]; float radius; } data = {NULL}; */ /* UNUSED */
+       if (me) {
+               em_vertoffs= me->totvert+1;     /* max index array */
+
+               bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0f));
+               EM_backbuf_checkAndSelectVerts_obmode(me, select==LEFTMOUSE);
+               EM_free_backbuf();
+
+               paintvert_flush_flags(ob);
+       }
+}
+
+
 static void nurbscurve_circle_doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
 {
        struct {ViewContext *vc; short select; int mval[2]; float radius; } *data = userData;
@@ -2258,7 +2441,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
        
        select= (gesture_mode==GESTURE_MODAL_SELECT);
 
-       if( CTX_data_edit_object(C) || paint_facesel_test(obact) ||
+       if( CTX_data_edit_object(C) || paint_facesel_test(obact) || paint_vertsel_test(obact) ||
                (obact && (obact->mode & (OB_MODE_PARTICLE_EDIT|OB_MODE_POSE))) )
        {
                ViewContext vc;
@@ -2278,6 +2461,10 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
                        paint_facesel_circle_select(&vc, select, mval, (float)radius);
                        WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obact->data);
                }
+               else if(paint_vertsel_test(obact)) {
+                       paint_vertsel_circle_select(&vc, select, mval, (float)radius);
+                       WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obact->data);
+               }
                else if(obact->mode & OB_MODE_POSE)
                        pose_circle_select(&vc, select, mval, (float)radius);
                else
index 6ad60ac2df9c1f9baf025c68dbd04266c54e9790..25bb4958c977027c9ed32bc8d08ea8c4ff09c90c 100644 (file)
@@ -125,7 +125,7 @@ typedef struct TFace {
 
 #define ME_EDIT_PAINT_MASK (1 << 3)
 #define ME_EDIT_MIRROR_TOPO (1 << 4)
-
+#define ME_EDIT_VERT_SEL (1 << 5)
 
 /* me->flag */
 /* #define ME_ISDONE           1 */
index 8750ee9e9066bcb6c47b95886f41308a937dbd84..f32f8d626deb68232a06aecf423becc4853b72fd 100644 (file)
@@ -62,9 +62,14 @@ struct bGPdata;
 typedef struct bDeformGroup {
        struct bDeformGroup *next, *prev;
        char name[32];
+       /* need this flag for locking weights */
+       char flag, pad[7];
 } bDeformGroup;
 #define MAX_VGROUP_NAME 32
 
+/* bDeformGroup->flag */
+#define DG_LOCK_WEIGHT 1
+
 /**
  * The following illustrates the orientation of the 
  * bounding box in local space
index 5f20432d6f8cbacf17e86d39fc4ef880b5e390a9..9f176a22848d7a792f83b33947867130b39a30fa 100644 (file)
@@ -759,9 +759,10 @@ typedef struct ToolSettings {
        short snap_flag, snap_target;
        short proportional, prop_mode;
        char proportional_objects; /* proportional edit, object mode */
-       char pad[3];
+       char pad[5];
 
-       int auto_normalize; /*auto normalizing mode in wpaint*/
+       char auto_normalize; /*auto normalizing mode in wpaint*/
+       char multipaint; /* paint multiple bones in wpaint */
 
        short sculpt_paint_settings; /* user preferences for sculpt and paint */
        short pad1;
index b0554ea5b4f89f2828f84c44cb342ebbc78b3fc7..a439ec471cd40924c56e4a13cc134b8b82958c97 100644 (file)
@@ -90,6 +90,24 @@ void rna_Mesh_update_draw(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA
        }
 }
 
+
+void rna_Mesh_update_vertmask(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+       Mesh* me = ptr->data;
+       if ((me->editflag & ME_EDIT_VERT_SEL) && (me->editflag & ME_EDIT_PAINT_MASK)) {
+               me->editflag ^= ME_EDIT_PAINT_MASK;
+       }
+       rna_Mesh_update_draw(bmain, scene, ptr);
+}
+
+void rna_Mesh_update_facemask(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+       Mesh* me = ptr->data;
+       if ((me->editflag & ME_EDIT_VERT_SEL) && (me->editflag & ME_EDIT_PAINT_MASK)) {
+               me->editflag ^= ME_EDIT_VERT_SEL;
+       }
+       rna_Mesh_update_draw(bmain, scene, ptr);
+}
 static void rna_MeshVertex_normal_get(PointerRNA *ptr, float *value)
 {
        MVert *mvert= (MVert*)ptr->data;
@@ -2075,8 +2093,14 @@ static void rna_def_mesh(BlenderRNA *brna)
        RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_PAINT_MASK);
        RNA_def_property_ui_text(prop, "Paint Mask", "Face selection masking for painting");
        RNA_def_property_ui_icon(prop, ICON_FACESEL_HLT, 0);
-       RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+       RNA_def_property_update(prop, 0, "rna_Mesh_update_facemask");
 
+       
+       prop= RNA_def_property(srna, "use_paint_mask_vertex", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_VERT_SEL);
+       RNA_def_property_ui_text(prop, "Vertex Selection", "Vertex selection masking for painting (weight paint only)");
+       RNA_def_property_ui_icon(prop, ICON_VERTEXSEL, 0);
+       RNA_def_property_update(prop, 0, "rna_Mesh_update_vertmask");
 
        /* readonly editmesh info - use for extrude menu */
        prop= RNA_def_property(srna, "total_vert_sel", PROP_INT, PROP_UNSIGNED);
index e7b5529af02a4cb51ff27df831e8cf6d373995de..ee9d016dfe29331565af8032e14c843f41b7054a 100644 (file)
@@ -1265,6 +1265,11 @@ static void rna_def_vertex_group(BlenderRNA *brna)
        RNA_def_struct_name_property(srna, prop);
        RNA_def_property_string_funcs(prop, NULL, NULL, "rna_VertexGroup_name_set");
        RNA_def_property_update(prop, NC_GEOM|ND_DATA|NA_RENAME, "rna_Object_internal_update_data"); /* update data because modifiers may use [#24761] */
+       
+       prop= RNA_def_property(srna, "lock_weight", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_ui_text(prop, "", "Maintain the relative weights for the group");
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", 0);
+       RNA_def_property_update(prop, NC_GEOM|ND_DATA|NA_RENAME, "rna_Object_internal_update_data"); /* update data because modifiers may use [#24761] */
 
        prop= RNA_def_property(srna, "index", PROP_INT, PROP_UNSIGNED);
        RNA_def_property_clear_flag(prop, PROP_EDITABLE);
index 76d7c3153d839b034a497726b478e3b652de3b4b..025bea8d190efad4091bb3c844057230d328375d 100644 (file)
@@ -1044,6 +1044,22 @@ static KeyingSet *rna_Scene_keying_set_new(Scene *sce, ReportList *reports, cons
        }
 }
 
+
+
+/* note: without this, when Multi-Paint is activated/deactivated, the colors
+ * will not change right away when multiple bones are selected, this function
+ * is not for general use and only for the few cases where changing scene
+ * settings and NOT for general purpose updates, possibly this should be
+ * given its own notifier. */
+static void rna_Scene_update_active_object_data(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+       Object *ob= OBACT;
+       if(ob) {
+               DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+               WM_main_add_notifier(NC_OBJECT|ND_DRAW, &ob->id);
+       }
+}
+
 #else
 
 static void rna_def_transform_orientation(BlenderRNA *brna)
@@ -1117,9 +1133,17 @@ static void rna_def_tool_settings(BlenderRNA  *brna)
        
        prop = RNA_def_property(srna, "use_auto_normalize", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "auto_normalize", 1);
-       RNA_def_property_ui_text(prop, "WPaint Auto-Normalize", 
-               "Ensure all bone-deforming vertex groups add up to 1.0 while "
-                "weight painting");
+       RNA_def_property_ui_text(prop, "WPaint Auto-Normalize",
+                                "Ensure all bone-deforming vertex groups add up "
+                                "to 1.0 while weight painting");
+       RNA_def_property_update(prop, 0, "rna_Scene_update_active_object_data");
+
+       prop = RNA_def_property(srna, "use_multipaint", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "multipaint", 1);
+       RNA_def_property_ui_text(prop, "WPaint Multi-Paint",
+                                "Paint across all selected bones while "
+                                "weight painting");
+       RNA_def_property_update(prop, 0, "rna_Scene_update_active_object_data");
 
        prop= RNA_def_property(srna, "vertex_paint", PROP_POINTER, PROP_NONE);
        RNA_def_property_pointer_sdna(prop, NULL, "vpaint");