diff options
author | Campbell Barton <ideasman42@gmail.com> | 2012-12-22 12:19:27 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2012-12-22 12:19:27 +0400 |
commit | a735a2370b1e85dc555550cd604cf0434567d7ac (patch) | |
tree | a56232a3a451d4147334901d1f0a9e9c628724b1 | |
parent | 2abb727ced258796bf54aff637c502cd6554efb7 (diff) |
Weight gradient tool for weight paint mode
- blends from current weight into alpha zero.
- uses brush alpha & curve.
- respects weight paint vertex/face select modes.
- updates realtime.
Access With
- Alt+LMB (linear gradient)
- Ctrl+Alt+LMB (radial gradient)
note:
- WM_gesture_straightline_* are used but not well suited to this task, may end up replacing with own modal operator.
- Key handling works but needs to be done better.
5 files changed, 264 insertions, 0 deletions
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 91132a72b07..09b32cd0c56 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -971,6 +971,7 @@ class VIEW3D_PT_tools_weightpaint(View3DPanel, Panel): col.operator("object.vertex_group_transfer_weight", text="Transfer Weights") col.operator("object.vertex_group_limit_total", text="Limit Total") col.operator("object.vertex_group_fix", text="Fix Deforms") + col.operator("paint.weight_gradient") class VIEW3D_PT_tools_weightpaint_options(Panel, View3DPaintPanel): diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 162e2fa15d6..cf55c93efe4 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -89,6 +89,12 @@ void PAINT_OT_weight_from_bones(struct wmOperatorType *ot); void PAINT_OT_weight_sample(struct wmOperatorType *ot); void PAINT_OT_weight_sample_group(struct wmOperatorType *ot); +enum { + WPAINT_GRADIENT_TYPE_LINEAR, + WPAINT_GRADIENT_TYPE_RADIAL +}; +void PAINT_OT_weight_gradient(struct wmOperatorType *ot); + void PAINT_OT_vertex_paint_toggle(struct wmOperatorType *ot); void PAINT_OT_vertex_paint(struct wmOperatorType *ot); diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index 40dcb92f087..10b9f26dbcd 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -475,6 +475,7 @@ void ED_operatortypes_paint(void) WM_operatortype_append(PAINT_OT_weight_paint); WM_operatortype_append(PAINT_OT_weight_set); WM_operatortype_append(PAINT_OT_weight_from_bones); + WM_operatortype_append(PAINT_OT_weight_gradient); WM_operatortype_append(PAINT_OT_weight_sample); WM_operatortype_append(PAINT_OT_weight_sample_group); @@ -710,6 +711,9 @@ void ED_keymap_paint(wmKeyConfig *keyconf) WM_keymap_verify_item(keymap, "PAINT_OT_weight_sample", LEFTMOUSE, KM_PRESS, KM_CTRL, 0); WM_keymap_verify_item(keymap, "PAINT_OT_weight_sample_group", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0); + RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_weight_gradient", LEFTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "type", WPAINT_GRADIENT_TYPE_LINEAR); + RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_weight_gradient", LEFTMOUSE, KM_PRESS, KM_ALT | KM_CTRL, 0)->ptr, "type", WPAINT_GRADIENT_TYPE_RADIAL); + WM_keymap_add_item(keymap, "PAINT_OT_weight_set", KKEY, KM_PRESS, KM_SHIFT, 0); diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 7134f1c2367..1299a3bf118 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -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); +} diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 05e949d781e..b5f1d590f37 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -4011,6 +4011,7 @@ static void gesture_straightline_modal_keymap(wmKeyConfig *keyconf) /* assign map to operators */ WM_modalkeymap_assign(keymap, "IMAGE_OT_sample_line"); + WM_modalkeymap_assign(keymap, "PAINT_OT_weight_gradient"); } |