forked from bartvdbraak/blender
svn merge ^/trunk/blender -r40367:40368 --- raddish weight paint merge
This commit is contained in:
commit
7126a4699e
@ -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,16 +860,60 @@ 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);
|
||||
@ -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);
|
||||
@ -903,17 +949,22 @@ static void add_weight_mcol_dm(Object *ob, DerivedMesh *dm)
|
||||
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);
|
||||
@ -5063,6 +5068,10 @@ 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"
|
||||
@ -704,6 +706,10 @@ static void vgroup_normalize(Object *ob)
|
||||
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));
|
||||
@ -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) {
|
||||
@ -784,6 +1209,10 @@ static void vgroup_normalize_all(Object *ob, int lock_active)
|
||||
float lock_iweight= 1.0f;
|
||||
int j;
|
||||
|
||||
if(use_vert_sel && !(mvert[i].flag & SELECT)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tot_weight= 0.0f;
|
||||
dw_act= NULL;
|
||||
dvert = dvert_array[i];
|
||||
@ -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,6 +1284,35 @@ 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;
|
||||
@ -857,6 +1320,10 @@ static void vgroup_invert(Object *ob, int auto_assign, int auto_remove)
|
||||
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));
|
||||
@ -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) {
|
||||
@ -980,6 +1451,10 @@ static void vgroup_clean(Object *ob, float eul, int keep_single)
|
||||
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);
|
||||
|
||||
/* only the active group */
|
||||
@ -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);
|
||||
@ -1010,11 +1489,20 @@ static void vgroup_clean_all(Object *ob, float eul, int keep_single)
|
||||
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,11 +474,15 @@ 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);
|
||||
|
||||
if(selected) {
|
||||
@ -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,11 +1194,453 @@ 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;
|
||||
|
||||
@ -1198,21 +1655,114 @@ 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);
|
||||
/* TODO: De-duplicate the simple weight paint - jason */
|
||||
/* ... or not, since its <10 SLOC - campbell */
|
||||
|
||||
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);
|
||||
/* 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);
|
||||
|
||||
uw->weight= dw->weight;
|
||||
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);
|
||||
|
||||
do_weight_paint_auto_normalize(me->dvert+j, vgroup, validmap);
|
||||
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;
|
||||
|
||||
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,9 +2026,13 @@ 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) {
|
||||
@ -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) {
|
||||
@ -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,6 +2208,8 @@ 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;
|
||||
@ -3013,6 +3038,15 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
|
||||
}
|
||||
}
|
||||
|
||||
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,9 +2181,15 @@ 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);
|
||||
RNA_def_property_int_funcs(prop, "rna_Mesh_tot_vert_get", NULL, NULL);
|
||||
|
@ -1267,6 +1267,11 @@ static void rna_def_vertex_group(BlenderRNA *brna)
|
||||
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);
|
||||
RNA_def_property_int_funcs(prop, "rna_VertexGroup_index_get", NULL, NULL);
|
||||
|
@ -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)
|
||||
@ -1120,8 +1136,16 @@ 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");
|
||||
"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");
|
||||
|
Loading…
Reference in New Issue
Block a user