Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/sculpt_paint/paint_vertex.c')
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c759
1 files changed, 587 insertions, 172 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 90ca1a6b18a..197231124fc 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -43,6 +43,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_math_color.h"
#include "BLI_memarena.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -224,7 +225,7 @@ static void do_shared_vertex_tesscol(Mesh *me)
{
/* if no mcol: do not do */
/* if tface: only the involved faces, otherwise all */
- const int use_face_sel = (me->editflag & ME_EDIT_PAINT_MASK);
+ const int use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL);
MFace *mface;
int a;
short *scolmain, *scol;
@@ -284,7 +285,7 @@ static void do_shared_vertex_tesscol(Mesh *me)
static void do_shared_vertexcol(Mesh *me, int do_tessface)
{
- const int use_face_sel = (me->editflag & ME_EDIT_PAINT_MASK);
+ const int use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL);
MPoly *mp;
float (*scol)[4];
int i, j, has_shared = 0;
@@ -292,7 +293,7 @@ static void do_shared_vertexcol(Mesh *me, int do_tessface)
/* if no mloopcol: do not do */
/* if mtexpoly: only the involved faces, otherwise all */
- if (me->mloopcol == 0 || me->totvert == 0 || me->totpoly == 0) return;
+ if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) return;
scol = MEM_callocN(sizeof(float) * me->totvert * 5, "scol");
@@ -346,14 +347,14 @@ static void make_vertexcol(Object *ob) /* single ob */
if (me->edit_btmesh) return;
/* copies from shadedisplist to mcol */
- if (!me->mloopcol) {
+ if (!me->mloopcol && me->totloop) {
if (!me->mcol) {
CustomData_add_layer(&me->fdata, CD_MCOL, CD_DEFAULT, NULL, me->totface);
}
if (!me->mloopcol) {
CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop);
}
- mesh_update_customdata_pointers(me, TRUE);
+ BKE_mesh_update_customdata_pointers(me, true);
}
update_tessface_data(ob, me);
@@ -372,42 +373,49 @@ static int wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active)
bDeformGroup *defgroup = BLI_findlink(&ob->defbase, vgroup_active);
if (defgroup) {
- bDeformGroup *curdef;
int mirrdef;
char name[MAXBONENAME];
flip_side_name(name, defgroup->name, FALSE);
-
- if (strcmp(name, defgroup->name) != 0) {
- for (curdef = ob->defbase.first, mirrdef = 0; curdef; curdef = curdef->next, mirrdef++) {
- if (!strcmp(curdef->name, name)) {
- break;
- }
- }
-
- if (curdef == NULL) {
- int olddef = ob->actdef; /* tsk, ED_vgroup_add sets the active defgroup */
- curdef = ED_vgroup_add_name(ob, name);
- ob->actdef = olddef;
- }
-
- /* curdef should never be NULL unless this is
- * a lamp and ED_vgroup_add_name fails */
- if (curdef) {
- return mirrdef;
+ mirrdef = defgroup_name_index(ob, name);
+ if (mirrdef == -1) {
+ int olddef = ob->actdef; /* tsk, ED_vgroup_add sets the active defgroup */
+ if (ED_vgroup_add_name(ob, name)) {
+ mirrdef = BLI_countlist(&ob->defbase) - 1;
}
+ ob->actdef = olddef;
}
+
+ /* curdef should never be NULL unless this is
+ * a lamp and ED_vgroup_add_name fails */
+ return mirrdef;
}
return -1;
}
-static void copy_vpaint_prev(VPaint *vp, unsigned int *lcol, int tot)
+static void free_vpaint_prev(VPaint *vp)
{
if (vp->vpaint_prev) {
MEM_freeN(vp->vpaint_prev);
vp->vpaint_prev = NULL;
+ vp->tot = 0;
}
+}
+
+static void free_wpaint_prev(VPaint *vp)
+{
+ if (vp->wpaint_prev) {
+ BKE_defvert_array_free(vp->wpaint_prev, vp->tot);
+ vp->wpaint_prev = NULL;
+ vp->tot = 0;
+ }
+}
+
+static void copy_vpaint_prev(VPaint *vp, unsigned int *lcol, int tot)
+{
+ free_vpaint_prev(vp);
+
vp->tot = tot;
if (lcol == NULL || tot == 0) return;
@@ -419,20 +427,16 @@ static void copy_vpaint_prev(VPaint *vp, unsigned int *lcol, int tot)
static void copy_wpaint_prev(VPaint *wp, MDeformVert *dverts, int dcount)
{
- if (wp->wpaint_prev) {
- free_dverts(wp->wpaint_prev, wp->tot);
- wp->wpaint_prev = NULL;
- }
+ free_wpaint_prev(wp);
if (dverts && dcount) {
wp->wpaint_prev = MEM_mallocN(sizeof(MDeformVert) * dcount, "wpaint prev");
wp->tot = dcount;
- copy_dverts(wp->wpaint_prev, dverts, dcount);
+ BKE_defvert_array_copy(wp->wpaint_prev, dverts, dcount);
}
}
-
void vpaint_fill(Object *ob, unsigned int paintcol)
{
Mesh *me;
@@ -447,7 +451,7 @@ void vpaint_fill(Object *ob, unsigned int paintcol)
if (!me->mloopcol) return; /* possible we can't make mcol's */
- selected = (me->editflag & ME_EDIT_PAINT_MASK);
+ selected = (me->editflag & ME_EDIT_PAINT_FACE_SEL);
mp = me->mpoly;
for (i = 0; i < me->totpoly; i++, mp++) {
@@ -657,11 +661,11 @@ BLI_INLINE unsigned int mcol_sub(unsigned int col1, unsigned int col2, int fac)
cp = (unsigned char *)&col;
temp = cp1[0] - ((fac * cp2[0]) / 255);
- cp1[0] = (temp < 0) ? 0 : temp;
+ cp[0] = (temp < 0) ? 0 : temp;
temp = cp1[1] - ((fac * cp2[1]) / 255);
- cp1[1] = (temp < 0) ? 0 : temp;
+ cp[1] = (temp < 0) ? 0 : temp;
temp = cp1[2] - ((fac * cp2[2]) / 255);
- cp1[2] = (temp < 0) ? 0 : temp;
+ cp[2] = (temp < 0) ? 0 : temp;
cp[3] = 255;
return col;
@@ -851,46 +855,58 @@ static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x
}
/* whats _dl mean? */
-static float calc_vp_strength_dl(VPaint *vp, ViewContext *vc, const float vert_nor[3],
- const float mval[2], const float brush_size_pressure)
+static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co[3],
+ const float mval[2], const float brush_size_pressure, float rgba[4])
{
- float vertco[2];
+ float co_ss[2]; /* screenspace */
- if (ED_view3d_project_float_global(vc->ar, vert_nor, vertco, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ if (ED_view3d_project_float_object(vc->ar,
+ co, co_ss,
+ V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
+ {
float delta[2];
float dist_squared;
- sub_v2_v2v2(delta, mval, vertco);
+ sub_v2_v2v2(delta, mval, co_ss);
dist_squared = dot_v2v2(delta, delta); /* len squared */
if (dist_squared <= brush_size_pressure * brush_size_pressure) {
Brush *brush = paint_brush(&vp->paint);
const float dist = sqrtf(dist_squared);
+ if (brush->mtex.tex && rgba) {
+ if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
+ BKE_brush_sample_tex_3D(vc->scene, brush, co, rgba, 0, NULL);
+ }
+ else {
+ const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */
+ BKE_brush_sample_tex_3D(vc->scene, brush, co_ss_3d, rgba, 0, NULL);
+ }
+ }
return BKE_brush_curve_strength_clamp(brush, dist, brush_size_pressure);
}
}
-
+ if (rgba)
+ zero_v4(rgba);
return 0.0f;
}
-static float calc_vp_alpha_dl(VPaint *vp, ViewContext *vc,
- float vpimat[3][3], const float *vert_nor,
+static float calc_vp_alpha_col_dl(VPaint *vp, ViewContext *vc,
+ float vpimat[3][3], const DMCoNo *v_co_no,
const float mval[2],
- const float brush_size_pressure, const float brush_alpha_pressure)
+ const float brush_size_pressure, const float brush_alpha_pressure, float rgba[4])
{
- float strength = calc_vp_strength_dl(vp, vc, vert_nor, mval, brush_size_pressure);
+ float strength = calc_vp_strength_col_dl(vp, vc, v_co_no->co, mval, brush_size_pressure, rgba);
if (strength > 0.0f) {
float alpha = brush_alpha_pressure * strength;
if (vp->flag & VP_NORMALS) {
float dvec[3];
- const float *no = vert_nor + 3;
/* transpose ! */
- dvec[2] = dot_v3v3(vpimat[2], no);
+ dvec[2] = dot_v3v3(vpimat[2], v_co_no->no);
if (dvec[2] > 0.0f) {
- dvec[0] = dot_v3v3(vpimat[0], no);
- dvec[1] = dot_v3v3(vpimat[1], no);
+ dvec[0] = dot_v3v3(vpimat[0], v_co_no->no);
+ dvec[1] = dot_v3v3(vpimat[1], v_co_no->no);
alpha *= dvec[2] / len_v3(dvec);
}
@@ -908,7 +924,8 @@ static float calc_vp_alpha_dl(VPaint *vp, ViewContext *vc,
BLI_INLINE float wval_blend(const float weight, const float paintval, const float alpha)
{
- return (paintval * alpha) + (weight * (1.0f - alpha));
+ const float talpha = min_ff(alpha, 1.0f); /* blending with values over 1 doesn't make sense */
+ return (paintval * talpha) + (weight * (1.0f - talpha));
}
BLI_INLINE float wval_add(const float weight, const float paintval, const float alpha)
{
@@ -1009,7 +1026,7 @@ static float wpaint_blend(VPaint *wp, float weight, float weight_prev,
/* sets wp->weight to the closest weight value to vertex */
/* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */
-static int weight_sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewContext vc;
Mesh *me;
@@ -1019,22 +1036,23 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
me = BKE_mesh_from_object(vc.obact);
if (me && me->dvert && vc.v3d && vc.rv3d) {
- const int use_vert_sel = (me->editflag & ME_EDIT_VERT_SEL) != 0;
+ const int use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
int v_idx_best = -1;
unsigned int index;
view3d_operator_needs_opengl(C);
+ ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d);
if (use_vert_sel) {
- if (ED_mesh_pick_vert(C, me, event->mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE)) {
+ if (ED_mesh_pick_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, TRUE)) {
v_idx_best = index;
}
}
else {
- if (ED_mesh_pick_face_vert(C, me, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
+ if (ED_mesh_pick_face_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
v_idx_best = index;
}
- else if (ED_mesh_pick_face(C, me, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
+ else if (ED_mesh_pick_face(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
/* this relies on knowning the internal worksings of ED_mesh_pick_face_vert() */
BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations");
}
@@ -1104,7 +1122,7 @@ static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA
if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) {
const int defbase_tot = BLI_countlist(&vc.obact->defbase);
- const int use_vert_sel = (me->editflag & ME_EDIT_VERT_SEL) != 0;
+ const int use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
int *groups = MEM_callocN(defbase_tot * sizeof(int), "groups");
int found = FALSE;
unsigned int index;
@@ -1113,15 +1131,16 @@ static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA
win->eventstate->y - vc.ar->winrct.ymin};
view3d_operator_needs_opengl(C);
+ ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d);
if (use_vert_sel) {
- if (ED_mesh_pick_vert(C, me, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE)) {
+ if (ED_mesh_pick_vert(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, TRUE)) {
MDeformVert *dvert = &me->dvert[index];
found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups);
}
}
else {
- if (ED_mesh_pick_face(C, me, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
+ if (ED_mesh_pick_face(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
MPoly *mp = &me->mpoly[index];
unsigned int fidx = mp->totloop - 1;
@@ -1459,7 +1478,7 @@ static void enforce_locks(MDeformVert *odv, MDeformVert *ndv,
MDeformWeight *ndw;
MDeformWeight *odw;
- float changed_sum = 0.0f;
+ // float changed_sum = 0.0f; // UNUSED
char *change_status;
@@ -1488,7 +1507,7 @@ static void enforce_locks(MDeformVert *odv, MDeformVert *ndv,
}
else if (ndw->weight != odw->weight) { /* changed groups are handled here */
totchange += ndw->weight - odw->weight;
- changed_sum += ndw->weight;
+ // changed_sum += ndw->weight; // UNUSED
change_status[i] = 2; /* was altered already */
total_changed++;
} /* unchanged, unlocked bone groups are handled here */
@@ -1994,6 +2013,13 @@ static int set_wpaint(bContext *C, wmOperator *UNUSED(op)) /* toggle */
else {
mesh_octree_table(NULL, NULL, NULL, 'e');
mesh_mirrtopo_table(NULL, 'e');
+
+ if (me->editflag & ME_EDIT_PAINT_VERT_SEL) {
+ BKE_mesh_flush_select_from_verts(me);
+ }
+ else if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
+ BKE_mesh_flush_select_from_polys(me);
+ }
}
WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
@@ -2038,34 +2064,30 @@ struct WPaintData {
int *indexar;
int vgroup_active;
int vgroup_mirror;
- float *vertexcosnos;
+ DMCoNo *vertexcosnos;
float wpimat[3][3];
-
+
/* variables for auto normalize */
const char *vgroup_validmap; /* stores if vgroups tie to deforming bones or not */
const char *lock_flags;
int defbase_tot;
};
-static int wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNUSED(mouse[2]))
+/* ensure we have data on wpaint start, add if needed */
+static int wpaint_ensure_data(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- struct PaintStroke *stroke = op->customdata;
- ToolSettings *ts = scene->toolsettings;
- VPaint *wp = ts->wpaint;
Object *ob = CTX_data_active_object(C);
- struct WPaintData *wpd;
- Mesh *me;
+ Mesh *me = BKE_mesh_from_object(ob);
- float mat[4][4], imat[4][4];
-
if (scene->obedit) {
return FALSE;
}
-
- me = BKE_mesh_from_object(ob);
- if (me == NULL || me->totpoly == 0) return OPERATOR_PASS_THROUGH;
-
+
+ if (me == NULL || me->totpoly == 0) {
+ return FALSE;
+ }
+
/* if nothing was added yet, we make dverts and a vertex deform group */
if (!me->dvert) {
ED_vgroup_data_create(&me->id);
@@ -2104,6 +2126,25 @@ static int wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNU
return FALSE;
}
+ return TRUE;
+}
+
+static int wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNUSED(mouse[2]))
+{
+ Scene *scene = CTX_data_scene(C);
+ struct PaintStroke *stroke = op->customdata;
+ ToolSettings *ts = scene->toolsettings;
+ VPaint *wp = ts->wpaint;
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = BKE_mesh_from_object(ob);
+ struct WPaintData *wpd;
+
+ float mat[4][4], imat[4][4];
+
+ if (wpaint_ensure_data(C, op) == FALSE) {
+ return FALSE;
+ }
+
{
/* check if we are attempting to paint onto a locked vertex group,
* and other options disallow it from doing anything useful */
@@ -2145,6 +2186,11 @@ static int wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNU
if (me->editflag & ME_EDIT_MIRROR_X) {
wpd->vgroup_mirror = wpaint_mirror_vgroup_ensure(ob, wpd->vgroup_active);
}
+
+ {
+ UnifiedPaintSettings *ups = &ts->unified_paint_settings;
+ ups->draw_pressure = true;
+ }
return TRUE;
}
@@ -2166,7 +2212,15 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
unsigned int index, totindex;
float alpha;
float mval[2];
- int use_vert_sel;
+ bool use_vert_sel;
+ bool use_face_sel;
+ bool use_depth;
+
+ MDeformWeight *(*dw_func)(MDeformVert *, const int) =
+ (brush->vertexpaint_tool == PAINT_BLEND_BLUR) ?
+ ((wp->flag & VP_ONLYVGROUP) ?
+ (MDeformWeight *(*)(MDeformVert *, const int))defvert_find_index :
+ defvert_verify_index) : NULL;
const float pressure = RNA_float_get(itemptr, "pressure");
const float brush_size_pressure = BKE_brush_size_get(scene, brush) * (BKE_brush_use_size_pressure(scene, brush) ? pressure : 1.0f);
@@ -2183,23 +2237,19 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
ED_region_tag_redraw(CTX_wm_region(C));
return;
}
-
+
vc = &wpd->vc;
ob = vc->obact;
me = ob->data;
indexar = wpd->indexar;
view3d_operator_needs_opengl(C);
-
+ ED_view3d_init_mats_rv3d(ob, vc->rv3d);
+
/* load projection matrix */
mult_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat);
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;
@@ -2223,32 +2273,39 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
swap_m4m4(wpd->vc.rv3d->persmat, mat);
- use_vert_sel = (me->editflag & ME_EDIT_VERT_SEL) != 0;
+ use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ use_depth = (vc->v3d->flag & V3D_ZBUF_SELECT);
/* 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->totpoly, mval[0], mval[1], brush_size_pressure);
- me->editflag |= use_vert_sel ? ME_EDIT_VERT_SEL : 0;
- }
- else {
- indexar[0] = view3d_sample_backbuf(vc, mval[0], mval[1]);
- if (indexar[0]) totindex = 1;
- else totindex = 0;
- }
+ if (use_depth) {
+ if (wp->flag & VP_AREA) {
+ /* Ugly hack, to avoid drawing vertex index when getting the face index buffer - campbell */
+ me->editflag &= ~ME_EDIT_PAINT_VERT_SEL;
+ totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure);
+ me->editflag |= use_vert_sel ? ME_EDIT_PAINT_VERT_SEL : 0;
+ }
+ else {
+ indexar[0] = view3d_sample_backbuf(vc, mval[0], mval[1]);
+ if (indexar[0]) totindex = 1;
+ else totindex = 0;
+ }
- if ((me->editflag & ME_EDIT_PAINT_MASK) && me->mpoly) {
- for (index = 0; index < totindex; index++) {
- if (indexar[index] && indexar[index] <= me->totpoly) {
- MPoly *mpoly = ((MPoly *)me->mpoly) + (indexar[index] - 1);
-
- if ((mpoly->flag & ME_FACE_SEL) == 0) {
- indexar[index] = 0;
+ if (use_face_sel && me->mpoly) {
+ for (index = 0; index < totindex; index++) {
+ if (indexar[index] && indexar[index] <= me->totpoly) {
+ MPoly *mpoly = ((MPoly *)me->mpoly) + (indexar[index] - 1);
+
+ if ((mpoly->flag & ME_FACE_SEL) == 0) {
+ indexar[index] = 0;
+ }
}
}
}
}
+ else {
+ indexar = NULL;
+ }
/* make sure each vertex gets treated only once */
/* and calculate filter weight */
@@ -2257,80 +2314,126 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
paintweight = 0.0f;
else
paintweight = BKE_brush_weight_get(scene, brush);
-
- for (index = 0; index < totindex; index++) {
- if (indexar[index] && indexar[index] <= me->totpoly) {
- MPoly *mpoly = me->mpoly + (indexar[index] - 1);
- MLoop *ml = me->mloop + mpoly->loopstart;
- int i;
- if (use_vert_sel) {
- for (i = 0; i < mpoly->totloop; i++, ml++) {
- me->dvert[ml->v].flag = (me->mvert[ml->v].flag & SELECT);
+#define WP_BLUR_ACCUM(v_idx_var) \
+ { \
+ const unsigned int vidx = v_idx_var; \
+ const float fac = calc_vp_strength_col_dl(wp, vc, wpd->vertexcosnos[vidx].co, mval, brush_size_pressure, NULL); \
+ if (fac > 0.0f) { \
+ MDeformWeight *dw = dw_func(&me->dvert[vidx], wpi.vgroup_active); \
+ paintweight += dw ? (dw->weight * fac) : 0.0f; \
+ totw += fac; \
+ } \
+ } (void)0
+
+
+ if (use_depth) {
+ for (index = 0; index < totindex; index++) {
+ if (indexar[index] && indexar[index] <= me->totpoly) {
+ MPoly *mpoly = me->mpoly + (indexar[index] - 1);
+ MLoop *ml = me->mloop + mpoly->loopstart;
+ int i;
+
+ 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;
+ else {
+ for (i = 0; i < mpoly->totloop; i++, ml++) {
+ me->dvert[ml->v].flag = 1;
+ }
}
- }
-
- if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
- MDeformWeight *dw, *(*dw_func)(MDeformVert *, const int);
-
- if (wp->flag & VP_ONLYVGROUP)
- dw_func = (MDeformWeight *(*)(MDeformVert *, const int))defvert_find_index;
- else
- dw_func = defvert_verify_index;
-
- ml = me->mloop + mpoly->loopstart;
- for (i = 0; i < mpoly->totloop; i++, ml++) {
- unsigned int vidx = ml->v;
- const float fac = calc_vp_strength_dl(wp, vc, wpd->vertexcosnos + 6 * vidx, mval, brush_size_pressure);
- if (fac > 0.0f) {
- dw = dw_func(&me->dvert[vidx], wpi.vgroup_active);
- paintweight += dw ? (dw->weight * fac) : 0.0f;
- totw += fac;
+
+ if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
+ ml = me->mloop + mpoly->loopstart;
+ for (i = 0; i < mpoly->totloop; i++, ml++) {
+ WP_BLUR_ACCUM(ml->v);
}
}
}
}
}
-
+ else {
+ const unsigned int totvert = me->totvert;
+ unsigned int i;
+
+ /* in the case of face selection we need to flush */
+ if (use_vert_sel || use_face_sel) {
+ for (i = 0; i < totvert; i++) {
+ me->dvert[i].flag = me->mvert[i].flag & SELECT;
+ }
+ }
+ else {
+ for (i = 0; i < totvert; i++) {
+ me->dvert[i].flag = SELECT;
+ }
+ }
+
+ if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
+ for (i = 0; i < totvert; i++) {
+ WP_BLUR_ACCUM(i);
+ }
+ }
+ }
+
+#undef WP_BLUR_ACCUM
+
+
if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
paintweight /= totw;
}
- for (index = 0; index < totindex; index++) {
+#define WP_PAINT(v_idx_var) \
+ { \
+ unsigned int vidx = v_idx_var; \
+ if (me->dvert[vidx].flag) { \
+ alpha = calc_vp_alpha_col_dl(wp, vc, wpd->wpimat, &wpd->vertexcosnos[vidx], \
+ mval, brush_size_pressure, brush_alpha_pressure, NULL); \
+ if (alpha) { \
+ do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight); \
+ } \
+ me->dvert[vidx].flag = 0; \
+ } \
+ } (void)0
+
+ if (use_depth) {
+ for (index = 0; index < totindex; index++) {
- if (indexar[index] && indexar[index] <= me->totpoly) {
- MPoly *mpoly = me->mpoly + (indexar[index] - 1);
- MLoop *ml = me->mloop + mpoly->loopstart;
- int i;
-
- for (i = 0; i < mpoly->totloop; i++, ml++) {
- unsigned int vidx = ml->v;
-
- if (me->dvert[vidx].flag) {
- alpha = calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos + 6 * vidx,
- mval, brush_size_pressure, brush_alpha_pressure);
- if (alpha) {
- do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight);
- }
- me->dvert[vidx].flag = 0;
+ if (indexar[index] && indexar[index] <= me->totpoly) {
+ MPoly *mpoly = me->mpoly + (indexar[index] - 1);
+ MLoop *ml = me->mloop + mpoly->loopstart;
+ int i;
+
+ for (i = 0; i < mpoly->totloop; i++, ml++) {
+ WP_PAINT(ml->v);
}
}
}
}
+ else {
+ const unsigned int totvert = me->totvert;
+ unsigned int i;
+
+ for (i = 0; i < totvert; i++) {
+ WP_PAINT(i);
+ }
+ }
+#undef WP_PAINT
/* *** free wpi members */
MEM_freeN((void *)wpi.defbase_sel);
- /* *** don't freeing wpi members */
+ /* *** done freeing wpi members */
swap_m4m4(vc->rv3d->persmat, mat);
-
+
+ {
+ UnifiedPaintSettings *ups = &ts->unified_paint_settings;
+ ups->pressure_value = pressure;
+ }
+
DAG_id_tag_update(ob->data, 0);
ED_region_tag_redraw(vc->ar);
}
@@ -2371,14 +2474,19 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
}
}
}
-
+
+ {
+ UnifiedPaintSettings *ups = &ts->unified_paint_settings;
+ ups->draw_pressure = false;
+ }
+
DAG_id_tag_update(ob->data, 0);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
}
-static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int retval;
@@ -2424,7 +2532,7 @@ void PAINT_OT_weight_paint(wmOperatorType *ot)
RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
}
-static int weight_paint_set_exec(bContext *C, wmOperator *UNUSED(op))
+static int weight_paint_set_exec(bContext *C, wmOperator *op)
{
struct Scene *scene = CTX_data_scene(C);
Object *obact = CTX_data_active_object(C);
@@ -2432,6 +2540,10 @@ static int weight_paint_set_exec(bContext *C, wmOperator *UNUSED(op))
Brush *brush = paint_brush(&ts->wpaint->paint);
float vgroup_weight = BKE_brush_weight_get(scene, brush);
+ if (wpaint_ensure_data(C, op) == FALSE) {
+ return OPERATOR_CANCELLED;
+ }
+
wpaint_fill(scene->toolsettings->wpaint, obact, vgroup_weight);
ED_region_tag_redraw(CTX_wm_region(C)); /* XXX - should redraw all 3D views */
return OPERATOR_FINISHED;
@@ -2477,6 +2589,10 @@ static int set_vpaint(bContext *C, wmOperator *op) /* toggle */
if (ob->mode & OB_MODE_VERTEX_PAINT) {
ob->mode &= ~OB_MODE_VERTEX_PAINT;
+
+ if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
+ BKE_mesh_flush_select_from_polys(me);
+ }
}
else {
ob->mode |= OB_MODE_VERTEX_PAINT;
@@ -2492,9 +2608,8 @@ static int set_vpaint(bContext *C, wmOperator *op) /* toggle */
BKE_paint_init(&vp->paint, PAINT_CURSOR_VERTEX_PAINT);
}
- if (me)
- /* update modifier stack for mapping requirements */
- DAG_id_tag_update(&me->id, 0);
+ /* update modifier stack for mapping requirements */
+ DAG_id_tag_update(&me->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
@@ -2548,7 +2663,7 @@ typedef struct VPaintData {
ViewContext vc;
unsigned int paintcol;
int *indexar;
- float *vertexcosnos;
+ DMCoNo *vertexcosnos;
float vpimat[3][3];
/* modify 'me->mcol' directly, since the derived mesh is drawing from this array,
@@ -2558,6 +2673,8 @@ typedef struct VPaintData {
/* mpoly -> mface mapping */
MemArena *polyfacemap_arena;
ListBase *polyfacemap;
+
+ bool is_texbrush;
} VPaintData;
static void vpaint_build_poly_facemap(struct VPaintData *vd, Mesh *me)
@@ -2594,6 +2711,7 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const fl
ToolSettings *ts = CTX_data_tool_settings(C);
struct PaintStroke *stroke = op->customdata;
VPaint *vp = ts->vpaint;
+ Brush *brush = paint_brush(&vp->paint);
struct VPaintData *vpd;
Object *ob = CTX_data_active_object(C);
Mesh *me;
@@ -2623,6 +2741,8 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const fl
vpd->indexar = get_indexarray(me);
vpd->paintcol = vpaint_get_current_col(vp);
+ vpd->is_texbrush = !(brush->vertexpaint_tool == PAINT_BLEND_BLUR) &&
+ brush->mtex.tex;
/* are we painting onto a modified mesh?,
* if not we can skip face map trickyness */
@@ -2644,16 +2764,20 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const fl
invert_m4_m4(imat, mat);
copy_m3_m4(vpd->vpimat, imat);
+ {
+ UnifiedPaintSettings *ups = &ts->unified_paint_settings;
+ ups->draw_pressure = true;
+ }
+
return 1;
}
-static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Object *ob,
+static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Mesh *me,
const unsigned int index, const float mval[2],
const float brush_size_pressure, const float brush_alpha_pressure)
{
ViewContext *vc = &vpd->vc;
Brush *brush = paint_brush(&vp->paint);
- Mesh *me = BKE_mesh_from_object(ob);
MPoly *mpoly = &me->mpoly[index];
MFace *mf;
MCol *mc;
@@ -2695,12 +2819,24 @@ static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Object *ob,
ml = me->mloop + mpoly->loopstart;
for (i = 0; i < mpoly->totloop; i++, ml++) {
- alpha = calc_vp_alpha_dl(vp, vc, vpd->vpimat,
- vpd->vertexcosnos + 6 * ml->v, mval,
- brush_size_pressure, brush_alpha_pressure);
+ float rgba[4];
+ unsigned int paintcol;
+ alpha = calc_vp_alpha_col_dl(vp, vc, vpd->vpimat,
+ &vpd->vertexcosnos[ml->v], mval,
+ brush_size_pressure, brush_alpha_pressure, rgba);
+
+ if (vpd->is_texbrush) {
+ float rgba_br[3];
+ rgb_uchar_to_float(rgba_br, (const unsigned char *)&vpd->paintcol);
+ mul_v3_v3(rgba_br, rgba);
+ rgb_float_to_uchar((unsigned char *)&paintcol, rgba_br);
+ }
+ else
+ paintcol = vpd->paintcol;
+
if (alpha > 0.0f) {
const int alpha_i = (int)(alpha * 255.0f);
- lcol[i] = vpaint_blend(vp, lcol[i], lcolorig[i], vpd->paintcol, alpha_i, brush_alpha_pressure_i);
+ lcol[i] = vpaint_blend(vp, lcol[i], lcolorig[i], paintcol, alpha_i, brush_alpha_pressure_i);
}
}
@@ -2754,14 +2890,11 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
RNA_float_get_array(itemptr, "mouse", mval);
view3d_operator_needs_opengl(C);
-
+ ED_view3d_init_mats_rv3d(ob, vc->rv3d);
+
/* load projection matrix */
mult_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat);
- mval[0] -= vc->ar->winrct.xmin;
- mval[1] -= vc->ar->winrct.ymin;
-
-
/* which faces are involved */
if (vp->flag & VP_AREA) {
totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure);
@@ -2772,7 +2905,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
else totindex = 0;
}
- if ((me->editflag & ME_EDIT_PAINT_MASK) && me->mpoly) {
+ if ((me->editflag & ME_EDIT_PAINT_FACE_SEL) && me->mpoly) {
for (index = 0; index < totindex; index++) {
if (indexar[index] && indexar[index] <= me->totpoly) {
MPoly *mpoly = ((MPoly *)me->mpoly) + (indexar[index] - 1);
@@ -2787,7 +2920,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
for (index = 0; index < totindex; index++) {
if (indexar[index] && indexar[index] <= me->totpoly) {
- vpaint_paint_poly(vp, vpd, ob, indexar[index] - 1, mval, brush_size_pressure, brush_alpha_pressure);
+ vpaint_paint_poly(vp, vpd, me, indexar[index] - 1, mval, brush_size_pressure, brush_alpha_pressure);
}
}
@@ -2799,6 +2932,11 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
do_shared_vertexcol(me, do_tessface);
}
+ {
+ UnifiedPaintSettings *ups = &ts->unified_paint_settings;
+ ups->pressure_value = pressure;
+ }
+
ED_region_tag_redraw(vc->ar);
if (vpd->use_fast_update == FALSE) {
@@ -2830,12 +2968,17 @@ static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
BLI_memarena_free(vpd->polyfacemap_arena);
}
+ {
+ UnifiedPaintSettings *ups = &ts->unified_paint_settings;
+ ups->draw_pressure = false;
+ }
+
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
MEM_freeN(vpd);
}
-static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int retval;
@@ -2929,3 +3072,275 @@ 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_object(grad_data->ar,
+ co, vs->sco,
+ V3D_PROJ_TEST_CLIP_BB | 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 {
+ vs->weight_orig = 0.0f;
+ vs->flag = VGRAD_STORE_NOP;
+ }
+ }
+ 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 {
+ BLI_assert(grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL);
+ alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div;
+ }
+ /* 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, const 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;
+ if (wp->wpaint_prev) {
+ BKE_defvert_array_free_elems(me->dvert, me->totvert);
+ BKE_defvert_array_copy(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;
+ DMGradient_vertStore *vert_cache;
+ 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};
+ const bool is_interactive = (gesture != NULL);
+ DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
+
+ DMGradient_userData data = {0};
+
+ if (is_interactive) {
+ 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_FACE_SEL) {
+ BKE_mesh_flush_select_from_polys(me);
+ }
+ }
+
+ vert_cache = gesture->userdata;
+ }
+ else {
+ data.is_init = true;
+ vert_cache = MEM_mallocN(sizeof(DMGradient_vertStore) * me->totvert, __func__);
+ }
+
+ 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_FACE_SEL | ME_EDIT_PAINT_VERT_SEL));
+ data.vert_cache = vert_cache;
+ 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);
+
+ if (is_interactive == false) {
+ MEM_freeN(vert_cache);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ int ret;
+
+ if (wpaint_ensure_data(C, op) == FALSE) {
+ return OPERATOR_CANCELLED;
+ }
+
+ 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);
+}