svn merge ^/trunk/blender -r40367:40368 --- raddish weight paint merge

This commit is contained in:
Campbell Barton 2011-09-22 16:09:27 +00:00
commit 7126a4699e
35 changed files with 1924 additions and 105 deletions

@ -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:

@ -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):

@ -1071,6 +1071,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()

@ -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):

@ -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);

@ -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) */

@ -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
@ -60,6 +61,7 @@
#include "BKE_paint.h"
#include "BKE_texture.h"
#include "BKE_multires.h"
#include "BKE_armature.h"
#include "BKE_particle.h"
#include "BKE_tessmesh.h"
#include "BKE_bvhutils.h"
@ -858,20 +860,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;
}
}
}
/* 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);
CLAMP(input, 0.0f, 1.0f);
if(coba)
do_colorband(coba, input, colf);
else
@ -890,7 +936,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; // UNUSED
MFace *mf = dm->getTessFaceArray(dm);
@ -902,18 +948,23 @@ static void add_weight_mcol_dm(Object *ob, DerivedMesh *dm)
BLI_array_declare(wlcol);
int i, j, totface=dm->getNumTessFaces(dm), totloop;
int *origIndex = dm->getVertDataArray(dm, CD_ORIGINDEX);
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) * totface*4*4, "weightmap");
/*first add colors to the tesselation faces*/
memset(wtcol, 0x55, sizeof (unsigned char) * totface*4*4);
for (i=0; i<totface; i++, mf++) {
/*origindex being NULL means we're operating on original mesh data*/
calc_weightpaint_vert_color(ob, coba, origIndex ? origIndex[mf->v1] : mf->v1, &wtcol[(i*4 + 0)*4]);
calc_weightpaint_vert_color(ob, coba, origIndex ? origIndex[mf->v2] : mf->v2, &wtcol[(i*4 + 1)*4]);
calc_weightpaint_vert_color(ob, coba, origIndex ? origIndex[mf->v3] : 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, origIndex ? origIndex[mf->v4] : 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);
}
CustomData_add_layer(&dm->faceData, CD_WEIGHT_MCOL, CD_ASSIGN, wtcol, totface);
@ -927,7 +978,7 @@ static void add_weight_mcol_dm(Object *ob, DerivedMesh *dm)
BLI_array_growone(wlcol);
calc_weightpaint_vert_color(ob, coba, origIndex ? origIndex[ml->v] : ml->v,
(unsigned char *)&wlcol[totloop]);
(unsigned char *)&wlcol[totloop], defbase_sel, selected, unselected, draw_flag);
}
}
@ -1045,6 +1096,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;
@ -1244,16 +1298,13 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
DM_add_face_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
orig = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
for(i=0; i<dm->numVertData; i++) *orig++= i;
orig = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
for(i=0; i<dm->numEdgeData; i++) *orig++= i;
orig = DM_get_face_data_layer(dm, CD_ORIGINDEX);
for(i=0; i<dm->numPolyData; i++) *orig++= i;
range_vni(DM_get_vert_data_layer(dm, CD_ORIGINDEX), dm->numVertData, 0);
range_vni(DM_get_edge_data_layer(dm, CD_ORIGINDEX), dm->numEdgeData, 0);
range_vni(DM_get_face_data_layer(dm, CD_ORIGINDEX), dm->numPolyData, 0);
}
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);
}
@ -1348,7 +1399,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 {
@ -1370,8 +1421,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);
}
/* add an orco layer if needed */

@ -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;
}

@ -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;

@ -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);
@ -5062,6 +5067,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;
@ -5092,6 +5101,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;
}

@ -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;
}
}
}
}

@ -241,6 +241,9 @@ int paintface_minmax(struct Object *ob, float *min, float *max);
void paintface_hide(struct Object *ob, const int unselected);
void paintface_reveal(struct Object *ob);
void paintvert_deselect_all_visible(struct Object *ob, int action, short flush_flags);
void paintvert_flush_flags(struct Object *ob);
/* object_vgroup.c */
#define WEIGHT_REPLACE 1

@ -56,6 +56,7 @@ struct Scene;
struct View3D;
struct ViewContext;
struct wmWindow;
struct MVert;
/* for derivedmesh drawing callbacks, for view3d_select, .... */

@ -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;

@ -248,6 +248,7 @@ int EDBM_mask_init_backbuf_border(ViewContext *vc, int mcords[][2], short tot, s
/* 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;
@ -303,6 +304,7 @@ int EDBM_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;

@ -624,3 +624,101 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, int select, int extend)
return OPERATOR_FINISHED;
}
/* (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);
}
}

@ -201,6 +201,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);

@ -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);

@ -50,6 +50,7 @@
#include "DNA_scene_types.h"
#include "DNA_particle_types.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_cellalloc.h"
#include "BLI_utildefines.h"
@ -62,6 +63,7 @@
#include "BKE_mesh.h"
#include "BKE_tessmesh.h"
#include "BKE_report.h"
#include "BKE_DerivedMesh.h"
#include "RNA_access.h"
#include "RNA_define.h"
@ -703,6 +705,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);
@ -714,6 +720,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) {
@ -723,6 +734,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) {
@ -738,6 +754,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;
@ -745,6 +1156,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));
@ -753,6 +1168,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) {
@ -774,6 +1194,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) {
@ -783,6 +1208,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;
@ -823,6 +1252,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];
@ -850,12 +1284,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);
@ -866,6 +1333,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) {
@ -979,6 +1450,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);
@ -988,6 +1463,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);
@ -1009,12 +1488,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;
@ -1844,6 +2332,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;

@ -5433,6 +5433,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)
{

@ -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 */

@ -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;

@ -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);

@ -65,6 +65,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"
@ -473,10 +474,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);
@ -511,7 +516,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);
@ -866,7 +876,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;
@ -904,7 +914,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) {
@ -931,15 +944,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;
}
}
}
@ -1179,14 +1194,456 @@ static void do_weight_paint_auto_normalize(MDeformVert *dvert,
}
}
static void do_weight_paint_vertex(VPaint *wp, Object *ob, int index,
float alpha, float paintweight, int flip,
int vgroup_mirror, char *validmap)
/* the active group should be involved in auto normalize */
static void do_weight_paint_auto_normalize_all_groups(MDeformVert *dvert, char *map, char do_auto_normalize)
{
// MDeformWeight *dw = dvert->dw;
float sum=0.0f, fac=0.0f;
int i, tot=0;
if (do_auto_normalize == FALSE)
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, char do_auto_normalize) {
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(do_auto_normalize == FALSE && 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
(void)vgroup_validmap;
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, char do_auto_normalize)
{
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, do_auto_normalize);
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, do_auto_normalize);
}
}
}
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;
char do_auto_normalize;
} 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, wpi->do_auto_normalize);
do_weight_paint_auto_normalize_all_groups(dv, wpi->vgroup_validmap, wpi->do_auto_normalize);
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;
}
/* 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);
@ -1197,22 +1654,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= -1; //BMESH_TODO 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);
/* 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, wpi->do_auto_normalize);
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_all_groups(me->dvert+j, wpi->vgroup_validmap, wpi->do_auto_normalize);
}
}
}
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;
do_weight_paint_auto_normalize(me->dvert+j, vgroup, validmap);
//uw->weight= dw->weight;
apply_mp_locks_normalize(me, wpi, j, uw, tdw, change, oldChange, oldw, neww);
}
}
}
}
@ -1309,16 +1859,15 @@ struct WPaintData {
/*variables for auto normalize*/
int auto_normalize;
char *vgroup_validmap; /*stores if vgroups tie to deforming bones or not*/
char *lock_flags;
int defbase_tot;
};
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;
@ -1330,7 +1879,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) {
@ -1339,10 +1888,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)
@ -1360,13 +1910,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))
@ -1407,7 +1957,9 @@ 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)
wpd->defbase_tot = BLI_countlist(&ob->defbase);
wpd->lock_flags = gen_lock_flags(ob, wpd->defbase_tot);
if (wpd->auto_normalize || ts->multipaint || wpd->lock_flags)
wpd->vgroup_validmap = wpaint_make_validmap(ob);
// if(qual & LR_CTRLKEY) {
@ -1474,10 +2026,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,
@ -1496,17 +2052,39 @@ 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= wpd->defbase_tot;
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= wpd->lock_flags;
wpi.vgroup_validmap= wpd->vgroup_validmap;
wpi.do_flip= RNA_boolean_get(itemptr, "pen_flip");
wpi.do_multipaint= (ts->multipaint != 0);
wpi.do_auto_normalize= (ts->auto_normalize != 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]);
@ -1552,8 +2130,15 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
MLoop *ml = me->mloop + mpoly->loopstart;
int i;
for (i=0; i<mpoly->totloop; i++, ml++) {
(me->dvert+ml->v)->flag = 1;
if(use_vert_sel) {
for (i=0; i<mpoly->totloop; i++, ml++) {
me->dvert[ml->v].flag = (me->mvert[ml->v].flag & SELECT);
}
}
else {
for (i=0; i<mpoly->totloop; i++, ml++) {
me->dvert[ml->v].flag = 1;
}
}
if(brush->vertexpaint_tool==VP_BLUR) {
@ -1570,7 +2155,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
if (dw) {
paintweight += dw->weight;
totw++;
}
}
}
}
}
@ -1586,19 +2171,24 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
int i;
for (i=0; i<mpoly->totloop; i++, ml++) {
if ((me->dvert+ml->v)->flag) {
alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*ml->v, mval, pressure);
unsigned int vidx= ml->v;
if (me->dvert[vidx].flag) {
alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*vidx, mval, pressure);
if(alpha != 0.0f) {
do_weight_paint_vertex(wp, ob, ml->v,
alpha, paintweight, flip, wpd->vgroup_mirror,
wpd->vgroup_validmap);
do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight);
}
(me->dvert+ml->v)->flag= 0;
me->dvert[vidx].flag= 0;
}
}
}
}
/* *** free wpi members */
MEM_freeN(wpi.defbase_sel);
/* *** dont freeing wpi members */
swap_m4m4(vc->rv3d->persmat, mat);
DAG_id_tag_update(ob->data, 0);
@ -1618,7 +2208,9 @@ static void wpaint_stroke_done(bContext *C, struct PaintStroke *stroke)
if (wpd->vgroup_validmap)
MEM_freeN(wpd->vgroup_validmap);
if(wpd->lock_flags)
MEM_freeN(wpd->lock_flags);
MEM_freeN(wpd);
}
@ -1704,7 +2296,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;

@ -550,7 +550,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);

@ -1745,6 +1745,31 @@ void mesh_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, BMVert
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, BMEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } *data = userData;
@ -3012,7 +3037,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);
}
@ -6604,6 +6638,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))
{
void **ptrs = userData;
@ -6712,6 +6772,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);
@ -6770,7 +6841,21 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
EDBM_free_index_arrays(em);
}
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);
bm_vertoffs = me->totvert+1;
dm->release(dm);
}
else {
bbs_mesh_solid(scene, ob);
}
}
break;
case OB_CURVE:

@ -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);

@ -501,7 +501,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;

@ -54,6 +54,11 @@
#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"
@ -204,6 +209,25 @@ static void EDBM_backbuf_checkAndSelectFaces(BMEditMesh *em, int select)
}
}
/* object mode, EM_ prefix is confusing here, rename? */
static void EDBM_backbuf_checkAndSelectVerts_obmode(Mesh *me, int select)
{
MVert *mv = me->mvert;
int a;
if (mv) {
for(a=1; a<=me->totvert; a++, mv++) {
if(EDBM_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 EDBM_backbuf_checkAndSelectTFaces(Mesh *me, int select)
{
MPoly *mpoly = me->mpoly;
@ -237,7 +261,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;
}
}
@ -733,6 +757,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 */
bm_vertoffs= me->totvert+1; /* max index array */
lasso_select_boundbox(&rect, mcords, moves);
EDBM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
EDBM_backbuf_checkAndSelectVerts_obmode(me, select);
EDBM_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;
@ -795,6 +901,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)
@ -1804,6 +1912,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);
}
@ -1840,6 +1951,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 ****** */
@ -1884,8 +2046,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
@ -2010,6 +2176,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) {
bm_vertoffs= me->totvert+1; /* max index array */
bbsel= EDBM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0f));
EDBM_backbuf_checkAndSelectVerts_obmode(me, select==LEFTMOUSE);
EDBM_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;
@ -2264,7 +2448,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;
@ -2284,6 +2468,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

@ -142,7 +142,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 */

@ -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

@ -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;

@ -95,6 +95,24 @@ void rna_Mesh_update_draw(Main *bmain, Scene *scene, PointerRNA *ptr)
}
}
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;
@ -2163,8 +2181,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);

@ -1266,6 +1266,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);

@ -1046,6 +1046,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)
@ -1119,9 +1135,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");