|
|
|
|
@@ -2939,3 +2939,255 @@ void PAINT_OT_weight_from_bones(wmOperatorType *ot)
|
|
|
|
|
/* properties */
|
|
|
|
|
ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* *** VGroups Gradient *** */
|
|
|
|
|
typedef struct DMGradient_vertStore {
|
|
|
|
|
float sco[2];
|
|
|
|
|
float weight_orig;
|
|
|
|
|
enum {
|
|
|
|
|
VGRAD_STORE_NOP = 0,
|
|
|
|
|
VGRAD_STORE_DW_EXIST = (1 << 0)
|
|
|
|
|
} flag;
|
|
|
|
|
} DMGradient_vertStore;
|
|
|
|
|
|
|
|
|
|
typedef struct DMGradient_userData {
|
|
|
|
|
struct ARegion *ar;
|
|
|
|
|
Scene *scene;
|
|
|
|
|
Mesh *me;
|
|
|
|
|
Brush *brush;
|
|
|
|
|
const float *sco_start; /* [2] */
|
|
|
|
|
const float *sco_end; /* [2] */
|
|
|
|
|
float sco_line_div; /* store (1.0f / len_v2v2(sco_start, sco_end)) */
|
|
|
|
|
int def_nr;
|
|
|
|
|
short is_init;
|
|
|
|
|
DMGradient_vertStore *vert_cache;
|
|
|
|
|
|
|
|
|
|
/* options */
|
|
|
|
|
short use_select;
|
|
|
|
|
short type;
|
|
|
|
|
float weightpaint;
|
|
|
|
|
} DMGradient_userData;
|
|
|
|
|
|
|
|
|
|
static void gradientVert__mapFunc(void *userData, int index, const float co[3],
|
|
|
|
|
const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
|
|
|
|
|
{
|
|
|
|
|
DMGradient_userData *grad_data = userData;
|
|
|
|
|
Mesh *me = grad_data->me;
|
|
|
|
|
|
|
|
|
|
if (grad_data->use_select == FALSE || (me->mvert[index].flag & SELECT)) {
|
|
|
|
|
DMGradient_vertStore *vs = &grad_data->vert_cache[index];
|
|
|
|
|
|
|
|
|
|
/* run first pass only, could be split into its own mapFunc
|
|
|
|
|
* the screen coords of the verts need to be cached because
|
|
|
|
|
* updating the mesh may move them about (entering feedback loop) */
|
|
|
|
|
if (grad_data->is_init) {
|
|
|
|
|
if (ED_view3d_project_float_global(grad_data->ar,
|
|
|
|
|
co, vs->sco,
|
|
|
|
|
V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
|
|
|
|
|
{
|
|
|
|
|
/* ok */
|
|
|
|
|
MDeformVert *dv = &me->dvert[index];
|
|
|
|
|
MDeformWeight *dw;
|
|
|
|
|
dw = defvert_find_index(dv, grad_data->def_nr);
|
|
|
|
|
if (dw) {
|
|
|
|
|
vs->weight_orig = dw->weight;
|
|
|
|
|
vs->flag |= VGRAD_STORE_DW_EXIST;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* no go */
|
|
|
|
|
copy_v2_fl(vs->sco, FLT_MAX);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* end init */
|
|
|
|
|
|
|
|
|
|
if (vs->sco[0] != FLT_MAX) {
|
|
|
|
|
float alpha;
|
|
|
|
|
|
|
|
|
|
if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) {
|
|
|
|
|
alpha = line_point_factor_v2(vs->sco, grad_data->sco_start, grad_data->sco_end);
|
|
|
|
|
}
|
|
|
|
|
else if (grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL) {
|
|
|
|
|
alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BLI_assert(0);
|
|
|
|
|
}
|
|
|
|
|
/* no need to clamp 'alpha' yet */
|
|
|
|
|
|
|
|
|
|
/* adjust weight */
|
|
|
|
|
alpha = BKE_brush_curve_strength_clamp(grad_data->brush, alpha, 1.0f);
|
|
|
|
|
|
|
|
|
|
if (alpha != 0.0f) {
|
|
|
|
|
MDeformVert *dv = &me->dvert[index];
|
|
|
|
|
MDeformWeight *dw = defvert_verify_index(dv, grad_data->def_nr);
|
|
|
|
|
// dw->weight = alpha; // testing
|
|
|
|
|
int tool = grad_data->brush->vertexpaint_tool;
|
|
|
|
|
float testw;
|
|
|
|
|
|
|
|
|
|
/* init if we just added */
|
|
|
|
|
testw = wpaint_blend_tool(tool, vs->weight_orig, grad_data->weightpaint, alpha * grad_data->brush->alpha);
|
|
|
|
|
CLAMP(testw, 0.0f, 1.0f);
|
|
|
|
|
dw->weight = testw;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
MDeformVert *dv = &me->dvert[index];
|
|
|
|
|
if (vs->flag & VGRAD_STORE_DW_EXIST) {
|
|
|
|
|
/* normally we NULL check, but in this case we know it exists */
|
|
|
|
|
MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr);
|
|
|
|
|
dw->weight = vs->weight_orig;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* wasn't originally existing, remove */
|
|
|
|
|
MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr);
|
|
|
|
|
if (dw) {
|
|
|
|
|
defvert_remove_group(dv, dw);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int paint_weight_gradient_modal(bContext *C, wmOperator *op, wmEvent *event)
|
|
|
|
|
{
|
|
|
|
|
int ret = WM_gesture_straightline_modal(C, op, event);
|
|
|
|
|
|
|
|
|
|
if (ret & OPERATOR_RUNNING_MODAL) {
|
|
|
|
|
if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { /* XXX, hardcoded */
|
|
|
|
|
/* generally crap! redo! */
|
|
|
|
|
WM_gesture_straightline_cancel(C, op);
|
|
|
|
|
ret &= ~OPERATOR_RUNNING_MODAL;
|
|
|
|
|
ret |= OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ret & OPERATOR_CANCELLED) {
|
|
|
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
|
|
|
VPaint *wp = ts->wpaint;
|
|
|
|
|
Object *ob = CTX_data_active_object(C);
|
|
|
|
|
Mesh *me = ob->data;
|
|
|
|
|
copy_dverts(me->dvert, wp->wpaint_prev, me->totvert);
|
|
|
|
|
free_wpaint_prev(wp);
|
|
|
|
|
|
|
|
|
|
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
|
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
|
|
|
|
|
}
|
|
|
|
|
else if (ret & OPERATOR_FINISHED) {
|
|
|
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
|
|
|
VPaint *wp = ts->wpaint;
|
|
|
|
|
free_wpaint_prev(wp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
wmGesture *gesture = op->customdata;
|
|
|
|
|
struct ARegion *ar = CTX_wm_region(C);
|
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
|
Object *ob = CTX_data_active_object(C);
|
|
|
|
|
Mesh *me = ob->data;
|
|
|
|
|
int x_start = RNA_int_get(op->ptr, "xstart");
|
|
|
|
|
int y_start = RNA_int_get(op->ptr, "ystart");
|
|
|
|
|
int x_end = RNA_int_get(op->ptr, "xend");
|
|
|
|
|
int y_end = RNA_int_get(op->ptr, "yend");
|
|
|
|
|
float sco_start[2] = {x_start, y_start};
|
|
|
|
|
float sco_end[2] = {x_end, y_end};
|
|
|
|
|
|
|
|
|
|
DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
|
|
|
|
|
|
|
|
|
|
DMGradient_userData data = {0};
|
|
|
|
|
|
|
|
|
|
if (gesture->userdata == NULL) {
|
|
|
|
|
VPaint *wp = scene->toolsettings->wpaint;
|
|
|
|
|
|
|
|
|
|
gesture->userdata = MEM_mallocN(sizeof(DMGradient_vertStore) * me->totvert, __func__);
|
|
|
|
|
data.is_init = TRUE;
|
|
|
|
|
|
|
|
|
|
copy_wpaint_prev(wp, me->dvert, me->totvert);
|
|
|
|
|
|
|
|
|
|
/* on init only, convert face -> vert sel */
|
|
|
|
|
if (me->editflag & ME_EDIT_PAINT_MASK) {
|
|
|
|
|
BKE_mesh_flush_select_from_polys(me->mvert, me->totvert,
|
|
|
|
|
me->mloop,
|
|
|
|
|
me->medge, me->totedge,
|
|
|
|
|
me->mpoly, me->totpoly);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data.ar = ar;
|
|
|
|
|
data.scene = scene;
|
|
|
|
|
data.me = ob->data;
|
|
|
|
|
data.sco_start = sco_start;
|
|
|
|
|
data.sco_end = sco_end;
|
|
|
|
|
data.sco_line_div = 1.0f / len_v2v2(sco_start, sco_end);
|
|
|
|
|
data.def_nr = ob->actdef - 1;
|
|
|
|
|
data.use_select = (me->editflag & (ME_EDIT_PAINT_MASK | ME_EDIT_VERT_SEL));
|
|
|
|
|
data.vert_cache = gesture->userdata;
|
|
|
|
|
data.type = RNA_enum_get(op->ptr, "type");
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
|
|
|
VPaint *wp = ts->wpaint;
|
|
|
|
|
struct Brush *brush = paint_brush(&wp->paint);
|
|
|
|
|
data.brush = brush;
|
|
|
|
|
data.weightpaint = BKE_brush_weight_get(scene, brush);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dm->foreachMappedVert(dm, gradientVert__mapFunc, &data);
|
|
|
|
|
|
|
|
|
|
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
|
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
|
|
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
|
|
|
|
{
|
|
|
|
|
int ret = WM_gesture_straightline_invoke(C, op, event);
|
|
|
|
|
if (ret & OPERATOR_RUNNING_MODAL) {
|
|
|
|
|
struct ARegion *ar = CTX_wm_region(C);
|
|
|
|
|
if (ar->regiontype == RGN_TYPE_WINDOW) {
|
|
|
|
|
if (event->type == LEFTMOUSE && event->val == KM_PRESS) { /* TODO, hardcoded, extend WM_gesture_straightline_ */
|
|
|
|
|
wmGesture *gesture = op->customdata;
|
|
|
|
|
gesture->mode = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PAINT_OT_weight_gradient(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* defined in DNA_space_types.h */
|
|
|
|
|
static EnumPropertyItem gradient_types[] = {
|
|
|
|
|
{WPAINT_GRADIENT_TYPE_LINEAR, "LINEAR", 0, "Linear", ""},
|
|
|
|
|
{WPAINT_GRADIENT_TYPE_RADIAL, "RADIAL", 0, "Radial", ""},
|
|
|
|
|
{0, NULL, 0, NULL, NULL}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
PropertyRNA *prop;
|
|
|
|
|
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name = "Weight Gradient";
|
|
|
|
|
ot->idname = "PAINT_OT_weight_gradient";
|
|
|
|
|
ot->description = "Sample a line and show it in Scope panels";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->invoke = paint_weight_gradient_invoke;
|
|
|
|
|
ot->modal = paint_weight_gradient_modal;
|
|
|
|
|
ot->exec = paint_weight_gradient_exec;
|
|
|
|
|
ot->poll = weight_paint_poll;
|
|
|
|
|
ot->cancel = WM_gesture_straightline_cancel;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
|
|
|
|
|
|
|
|
prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", "");
|
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
|
|
|
|
|
|
WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
|
|
|
|
|
}
|
|
|
|
|
|