Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/sculpt_paint/paint_vertex.c
| Show First 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | |||||
| #include "ED_view3d.h" | #include "ED_view3d.h" | ||||
| #include "bmesh.h" | #include "bmesh.h" | ||||
| #include "BKE_ccg.h" | #include "BKE_ccg.h" | ||||
| #include "sculpt_intern.h" | #include "sculpt_intern.h" | ||||
| #include "paint_intern.h" /* own include */ | #include "paint_intern.h" /* own include */ | ||||
| #define EPS_SATURATION 0.0005f | |||||
| /* Use for 'blur' brush, align with PBVH nodes, created and freed on each update. */ | /* Use for 'blur' brush, align with PBVH nodes, created and freed on each update. */ | ||||
| struct VPaintAverageAccum { | struct VPaintAverageAccum { | ||||
| uint len; | uint len; | ||||
| uint value[3]; | uint value[3]; | ||||
| }; | }; | ||||
| struct WPaintAverageAccum { | struct WPaintAverageAccum { | ||||
| uint len; | uint len; | ||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
| /* Returns true if vertex paint mode is active */ | /* Returns true if vertex paint mode is active */ | ||||
| int vertex_paint_mode_poll(bContext *C) | int vertex_paint_mode_poll(bContext *C) | ||||
| { | { | ||||
| Object *ob = CTX_data_active_object(C); | Object *ob = CTX_data_active_object(C); | ||||
| return ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totpoly; | return ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totpoly; | ||||
| } | } | ||||
| static int vertex_weight_paint_mode_poll(bContext *C) | |||||
| { | |||||
| Object *ob = CTX_data_active_object(C); | |||||
| return ob && (ob->mode == OB_MODE_VERTEX_PAINT || ob->mode == OB_MODE_WEIGHT_PAINT) && ((Mesh *)ob->data)->totpoly; | |||||
| } | |||||
| int vertex_paint_poll(bContext *C) | int vertex_paint_poll(bContext *C) | ||||
| { | { | ||||
| if (vertex_paint_mode_poll(C) && | if (vertex_paint_mode_poll(C) && | ||||
| BKE_paint_brush(&CTX_data_tool_settings(C)->vpaint->paint)) | BKE_paint_brush(&CTX_data_tool_settings(C)->vpaint->paint)) | ||||
| { | { | ||||
| ScrArea *sa = CTX_wm_area(C); | ScrArea *sa = CTX_wm_area(C); | ||||
| if (sa && sa->spacetype == SPACE_VIEW3D) { | if (sa && sa->spacetype == SPACE_VIEW3D) { | ||||
| ARegion *ar = CTX_wm_region(C); | ARegion *ar = CTX_wm_region(C); | ||||
| ▲ Show 20 Lines • Show All 192 Lines • ▼ Show 20 Lines | bool ED_vpaint_fill(Object *ob, uint paintcol) | ||||
| if (((me = BKE_mesh_from_object(ob)) == NULL) || | if (((me = BKE_mesh_from_object(ob)) == NULL) || | ||||
| (me->mloopcol == NULL && (make_vertexcol(ob) == false))) | (me->mloopcol == NULL && (make_vertexcol(ob) == false))) | ||||
| { | { | ||||
| return false; | return false; | ||||
| } | } | ||||
| const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; | const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; | ||||
| const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; | |||||
| mp = me->mpoly; | mp = me->mpoly; | ||||
| for (i = 0; i < me->totpoly; i++, mp++) { | for (i = 0; i < me->totpoly; i++, mp++) { | ||||
| MLoopCol *lcol = me->mloopcol + mp->loopstart; | MLoopCol *lcol = &me->mloopcol[mp->loopstart]; | ||||
| if (use_face_sel && !(mp->flag & ME_FACE_SEL)) | if (use_face_sel && !(mp->flag & ME_FACE_SEL)) | ||||
| continue; | continue; | ||||
| for (j = 0; j < mp->totloop; j++, lcol++) { | j = 0; | ||||
| do { | |||||
| uint vidx = me->mloop[mp->loopstart + j].v; | |||||
| const char v_flag = me->mvert[vidx].flag; | |||||
| if (v_flag || !use_vert_sel) { | |||||
| *(int *)lcol = paintcol; | *(int *)lcol = paintcol; | ||||
| } | } | ||||
| lcol++; | |||||
| j++; | |||||
| } while (j <= mp->totloop - 1); | |||||
| } | } | ||||
| /* remove stale me->mcol, will be added later */ | /* remove stale me->mcol, will be added later */ | ||||
| BKE_mesh_tessface_clear(me); | BKE_mesh_tessface_clear(me); | ||||
| DAG_id_tag_update(&me->id, 0); | DAG_id_tag_update(&me->id, 0); | ||||
| return true; | return true; | ||||
| ▲ Show 20 Lines • Show All 213 Lines • ▼ Show 20 Lines | while (a--) { | ||||
| cp[2] = gamtab[cp[2]]; | cp[2] = gamtab[cp[2]]; | ||||
| cp[3] = gamtab[cp[3]]; | cp[3] = gamtab[cp[3]]; | ||||
| cp += 4; | cp += 4; | ||||
| } | } | ||||
| } | } | ||||
| #endif | #endif | ||||
| BLI_INLINE uint mcol_blend(uint col1, uint col2, int fac) | BLI_INLINE uint mcol_blend( | ||||
| uint col1, uint col2, int fac) | |||||
| { | { | ||||
| uchar *cp1, *cp2, *cp; | uchar *cp1, *cp2, *cp; | ||||
| int mfac; | int mfac; | ||||
| uint col = 0; | uint col = 0; | ||||
| if (fac == 0) { | if (fac == 0) { | ||||
| return col1; | return col1; | ||||
| } | } | ||||
| if (fac >= 255) { | if (fac >= 255) { | ||||
| return col2; | return col2; | ||||
| } | } | ||||
| mfac = 255 - fac; | mfac = 255 - fac; | ||||
| cp1 = (uchar *)&col1; | cp1 = (uchar *)&col1; | ||||
| cp2 = (uchar *)&col2; | cp2 = (uchar *)&col2; | ||||
| cp = (uchar *)&col; | cp = (uchar *)&col; | ||||
| /* Updated to use the rgb squared color model which blends nicer. */ | /* Updated to use the rgb squared color model which blends nicer. */ | ||||
| int r1 = cp1[0] * cp1[0]; | int r1 = cp1[0] * cp1[0]; | ||||
| int g1 = cp1[1] * cp1[1]; | int g1 = cp1[1] * cp1[1]; | ||||
| int b1 = cp1[2] * cp1[2]; | int b1 = cp1[2] * cp1[2]; | ||||
| int a1 = cp1[3] * cp1[3]; | |||||
| int r2 = cp2[0] * cp2[0]; | int r2 = cp2[0] * cp2[0]; | ||||
| int g2 = cp2[1] * cp2[1]; | int g2 = cp2[1] * cp2[1]; | ||||
| int b2 = cp2[2] * cp2[2]; | int b2 = cp2[2] * cp2[2]; | ||||
| int a2 = cp2[3] * cp2[3]; | |||||
| cp[0] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * r1 + fac * r2), 255))); | cp[0] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * r1 + fac * r2), 255))); | ||||
| cp[1] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * g1 + fac * g2), 255))); | cp[1] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * g1 + fac * g2), 255))); | ||||
| cp[2] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * b1 + fac * b2), 255))); | cp[2] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * b1 + fac * b2), 255))); | ||||
| cp[3] = 255; | cp[3] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * a1 + fac * a2), 255))); | ||||
| return col; | return col; | ||||
| } | } | ||||
| BLI_INLINE uint mcol_add(uint col1, uint col2, int fac) | BLI_INLINE uint mcol_add( | ||||
| uint col1, uint col2, int fac) | |||||
| { | { | ||||
| uchar *cp1, *cp2, *cp; | uchar *cp1, *cp2, *cp; | ||||
| int temp; | int temp; | ||||
| uint col = 0; | uint col = 0; | ||||
| if (fac == 0) { | if (fac == 0) { | ||||
| return col1; | return col1; | ||||
| } | } | ||||
| cp1 = (uchar *)&col1; | cp1 = (uchar *)&col1; | ||||
| cp2 = (uchar *)&col2; | cp2 = (uchar *)&col2; | ||||
| cp = (uchar *)&col; | cp = (uchar *)&col; | ||||
| temp = cp1[0] + divide_round_i((fac * cp2[0]), 255); | temp = cp1[0] + divide_round_i((fac * cp2[0]), 255); | ||||
| cp[0] = (temp > 254) ? 255 : temp; | cp[0] = temp > 254 ? 255 : temp; | ||||
| temp = cp1[1] + divide_round_i((fac * cp2[1]), 255); | temp = cp1[1] + divide_round_i((fac * cp2[1]), 255); | ||||
| cp[1] = (temp > 254) ? 255 : temp; | cp[1] = temp > 254 ? 255 : temp; | ||||
| temp = cp1[2] + divide_round_i((fac * cp2[2]), 255); | temp = cp1[2] + divide_round_i((fac * cp2[2]), 255); | ||||
| cp[2] = (temp > 254) ? 255 : temp; | cp[2] = temp > 254 ? 255 : temp; | ||||
| cp[3] = 255; | temp = cp1[3] + divide_round_i((fac * cp2[3]), 255); | ||||
| cp[3] = (temp > 254) ? 255 : temp; | |||||
| return col; | return col; | ||||
| } | } | ||||
| BLI_INLINE uint mcol_sub(uint col1, uint col2, int fac) | BLI_INLINE uint mcol_sub( | ||||
| uint col1, uint col2, int fac) | |||||
| { | { | ||||
| uchar *cp1, *cp2, *cp; | uchar *cp1, *cp2, *cp; | ||||
| int temp; | int temp; | ||||
| uint col = 0; | uint col = 0; | ||||
| if (fac == 0) { | if (fac == 0) { | ||||
| return col1; | return col1; | ||||
| } | } | ||||
| cp1 = (uchar *)&col1; | cp1 = (uchar *)&col1; | ||||
| cp2 = (uchar *)&col2; | cp2 = (uchar *)&col2; | ||||
| cp = (uchar *)&col; | cp = (uchar *)&col; | ||||
| temp = cp1[0] - divide_round_i((fac * cp2[0]), 255); | temp = cp1[0] - divide_round_i((fac * cp2[0]), 255); | ||||
| cp[0] = (temp < 0) ? 0 : temp; | cp[0] = temp < 0 ? 0 : temp; | ||||
| temp = cp1[1] - divide_round_i((fac * cp2[1]), 255); | temp = cp1[1] - divide_round_i((fac * cp2[1]), 255); | ||||
| cp[1] = (temp < 0) ? 0 : temp; | cp[1] = temp < 0 ? 0 : temp; | ||||
| temp = cp1[2] - divide_round_i((fac * cp2[2]), 255); | temp = cp1[2] - divide_round_i((fac * cp2[2]), 255); | ||||
| cp[2] = (temp < 0) ? 0 : temp; | cp[2] = temp < 0 ? 0 : temp; | ||||
| cp[3] = 255; | temp = cp1[3] - divide_round_i((fac * cp2[3]), 255); | ||||
| cp[3] = temp < 0 ? 0 : temp; | |||||
| return col; | return col; | ||||
| } | } | ||||
| BLI_INLINE uint mcol_mul(uint col1, uint col2, int fac) | BLI_INLINE uint mcol_mul( | ||||
| uint col1, uint col2, int fac) | |||||
| { | { | ||||
| uchar *cp1, *cp2, *cp; | uchar *cp1, *cp2, *cp; | ||||
| int mfac; | int mfac; | ||||
| uint col = 0; | uint col = 0; | ||||
| if (fac == 0) { | if (fac == 0) { | ||||
| return col1; | return col1; | ||||
| } | } | ||||
| mfac = 255 - fac; | mfac = 255 - fac; | ||||
| cp1 = (uchar *)&col1; | cp1 = (uchar *)&col1; | ||||
| cp2 = (uchar *)&col2; | cp2 = (uchar *)&col2; | ||||
| cp = (uchar *)&col; | cp = (uchar *)&col; | ||||
| /* first mul, then blend the fac */ | /* first mul, then blend the fac */ | ||||
| cp[0] = divide_round_i(mfac * cp1[0] * 255 + fac * cp2[0] * cp1[0], 255 * 255); | cp[0] = divide_round_i(mfac * cp1[0] * 255 + fac * cp2[0] * cp1[0], 255 * 255); | ||||
| cp[1] = divide_round_i(mfac * cp1[1] * 255 + fac * cp2[1] * cp1[1], 255 * 255); | cp[1] = divide_round_i(mfac * cp1[1] * 255 + fac * cp2[1] * cp1[1], 255 * 255); | ||||
| cp[2] = divide_round_i(mfac * cp1[2] * 255 + fac * cp2[2] * cp1[2], 255 * 255); | cp[2] = divide_round_i(mfac * cp1[2] * 255 + fac * cp2[2] * cp1[2], 255 * 255); | ||||
| cp[3] = 255; | cp[3] = divide_round_i(mfac * cp1[3] * 255 + fac * cp2[3] * cp1[3], 255 * 255); | ||||
| return col; | return col; | ||||
| } | } | ||||
| BLI_INLINE uint mcol_lighten(uint col1, uint col2, int fac) | BLI_INLINE uint mcol_lighten( | ||||
| uint col1, uint col2, int fac) | |||||
| { | { | ||||
| uchar *cp1, *cp2, *cp; | uchar *cp1, *cp2, *cp; | ||||
| int mfac; | int mfac; | ||||
| uint col = 0; | uint col = 0; | ||||
| if (fac == 0) { | if (fac == 0) { | ||||
| return col1; | return col1; | ||||
| } | } | ||||
| Show All 11 Lines | BLI_INLINE uint mcol_lighten( | ||||
| * if the paint col is darker then the original, then ignore */ | * if the paint col is darker then the original, then ignore */ | ||||
| if (IMB_colormanagement_get_luminance_byte(cp1) > IMB_colormanagement_get_luminance_byte(cp2)) { | if (IMB_colormanagement_get_luminance_byte(cp1) > IMB_colormanagement_get_luminance_byte(cp2)) { | ||||
| return col1; | return col1; | ||||
| } | } | ||||
| cp[0] = divide_round_i(mfac * cp1[0] + fac * cp2[0], 255); | cp[0] = divide_round_i(mfac * cp1[0] + fac * cp2[0], 255); | ||||
| cp[1] = divide_round_i(mfac * cp1[1] + fac * cp2[1], 255); | cp[1] = divide_round_i(mfac * cp1[1] + fac * cp2[1], 255); | ||||
| cp[2] = divide_round_i(mfac * cp1[2] + fac * cp2[2], 255); | cp[2] = divide_round_i(mfac * cp1[2] + fac * cp2[2], 255); | ||||
| cp[3] = 255; | cp[3] = divide_round_i(mfac * cp1[3] + fac * cp2[3], 255); | ||||
| return col; | return col; | ||||
| } | } | ||||
| BLI_INLINE uint mcol_darken(uint col1, uint col2, int fac) | BLI_INLINE uint mcol_darken( | ||||
| uint col1, uint col2, int fac) | |||||
| { | { | ||||
| uchar *cp1, *cp2, *cp; | uchar *cp1, *cp2, *cp; | ||||
| int mfac; | int mfac; | ||||
| uint col = 0; | uint col = 0; | ||||
| if (fac == 0) { | if (fac == 0) { | ||||
| return col1; | return col1; | ||||
| } | } | ||||
| Show All 11 Lines | BLI_INLINE uint mcol_darken( | ||||
| * if the paint col is brighter then the original, then ignore */ | * if the paint col is brighter then the original, then ignore */ | ||||
| if (IMB_colormanagement_get_luminance_byte(cp1) < IMB_colormanagement_get_luminance_byte(cp2)) { | if (IMB_colormanagement_get_luminance_byte(cp1) < IMB_colormanagement_get_luminance_byte(cp2)) { | ||||
| return col1; | return col1; | ||||
| } | } | ||||
| cp[0] = divide_round_i((mfac * cp1[0] + fac * cp2[0]), 255); | cp[0] = divide_round_i((mfac * cp1[0] + fac * cp2[0]), 255); | ||||
| cp[1] = divide_round_i((mfac * cp1[1] + fac * cp2[1]), 255); | cp[1] = divide_round_i((mfac * cp1[1] + fac * cp2[1]), 255); | ||||
| cp[2] = divide_round_i((mfac * cp1[2] + fac * cp2[2]), 255); | cp[2] = divide_round_i((mfac * cp1[2] + fac * cp2[2]), 255); | ||||
| cp[3] = 255; | cp[3] = divide_round_i((mfac * cp1[3] + fac * cp2[3]), 255); | ||||
| return col; | |||||
| } | |||||
| BLI_INLINE uint mcol_colordodge( | |||||
| uint col1, uint col2, int fac) | |||||
| { | |||||
| uchar *cp1, *cp2, *cp; | |||||
| int mfac,temp; | |||||
| uint col = 0; | |||||
| if (fac == 0) { | |||||
| return col1; | |||||
| } | |||||
| mfac = 255 - fac; | |||||
| cp1 = (uchar *)&col1; | |||||
| cp2 = (uchar *)&col2; | |||||
| cp = (uchar *)&col; | |||||
| temp = (cp2[0] == 255) ? 255 : min_ii((cp1[0] * 225) / (255 - cp2[0]), 255); | |||||
| cp[0] = (mfac * cp1[0] + temp * fac) / 255; | |||||
| temp = (cp2[1] == 255) ? 255 : min_ii((cp1[1] * 225) / (255 - cp2[1]), 255); | |||||
| cp[1] = (mfac * cp1[1] + temp * fac) / 255; | |||||
| temp = (cp2[2] == 255) ? 255 : min_ii((cp1[2] * 225 )/ (255 - cp2[2]), 255); | |||||
| cp[2] = (mfac * cp1[2] + temp * fac) / 255; | |||||
| temp = (cp2[3] == 255) ? 255 : min_ii((cp1[3] * 225) / (255 - cp2[3]), 255); | |||||
| cp[3] = (mfac * cp1[3] + temp * fac) / 255; | |||||
| return col; | |||||
| } | |||||
| BLI_INLINE uint mcol_difference( | |||||
| uint col1, uint col2, int fac) | |||||
| { | |||||
| uchar *cp1, *cp2, *cp; | |||||
| int mfac, temp; | |||||
| uint col = 0; | |||||
| if (fac == 0) { | |||||
| return col1; | |||||
| } | |||||
| mfac = 255 - fac; | |||||
| cp1 = (uchar *)&col1; | |||||
| cp2 = (uchar *)&col2; | |||||
| cp = (uchar *)&col; | |||||
| temp = abs(cp1[0] - cp2[0]); | |||||
| cp[0] = (mfac * cp1[0] + temp * fac) / 255; | |||||
| temp = abs(cp1[1] - cp2[1]); | |||||
| cp[1] = (mfac * cp1[1] + temp * fac) / 255; | |||||
| temp = abs(cp1[2] - cp2[2]); | |||||
| cp[2] = (mfac * cp1[2] + temp * fac) / 255; | |||||
| temp = abs(cp1[3] - cp2[3]); | |||||
| cp[3] = (mfac * cp1[3] + temp * fac) / 255; | |||||
| return col; | |||||
| } | |||||
| BLI_INLINE uint mcol_screen( | |||||
| uint col1, uint col2, int fac) | |||||
| { | |||||
| uchar *cp1, *cp2, *cp; | |||||
| int mfac, temp; | |||||
| uint col = 0; | |||||
| if (fac == 0) { | |||||
| return col1; | |||||
| } | |||||
| mfac = 255 - fac; | |||||
| cp1 = (uchar *)&col1; | |||||
| cp2 = (uchar *)&col2; | |||||
| cp = (uchar *)&col; | |||||
| temp = max_ii(255 - (((255 - cp1[0]) * (255 - cp2[0])) / 255), 0); | |||||
| cp[0] = (mfac * cp1[0] + temp * fac) / 255; | |||||
| temp = max_ii(255 - (((255 - cp1[1]) * (255 - cp2[1])) / 255), 0); | |||||
| cp[1] = (mfac * cp1[1] + temp * fac) / 255; | |||||
| temp = max_ii(255 - (((255 - cp1[2]) * (255 - cp2[2])) / 255), 0); | |||||
| cp[2] = (mfac * cp1[2] + temp * fac) / 255; | |||||
| temp = max_ii(255 - (((255 - cp1[3]) * (255 - cp2[3])) / 255), 0); | |||||
| cp[3] = (mfac * cp1[3] + temp * fac) / 255; | |||||
| return col; | |||||
| } | |||||
| BLI_INLINE uint mcol_hardlight( | |||||
| uint col1, uint col2, int fac) | |||||
| { | |||||
| uchar *cp1, *cp2, *cp; | |||||
| int mfac, temp; | |||||
| uint col = 0; | |||||
| if (fac == 0) { | |||||
| return col1; | |||||
| } | |||||
| mfac = 255 - fac; | |||||
| cp1 = (uchar *)&col1; | |||||
| cp2 = (uchar *)&col2; | |||||
| cp = (uchar *)&col; | |||||
| int i = 0; | |||||
| for (i = 0; i < 4; i++) { | |||||
| if (cp2[i] > 127) { | |||||
| temp = 255 - ((255 - 2 * (cp2[i] - 127)) * (255 - cp1[i]) / 255); | |||||
| } | |||||
| else { | |||||
| temp = (2 * cp2[i] * cp1[i]) >> 8; | |||||
| } | |||||
| cp[i] = min_ii((mfac * cp1[i] + temp * fac) / 255, 255); | |||||
| } | |||||
| return col; | |||||
| } | |||||
| BLI_INLINE uint mcol_overlay( | |||||
| uint col1, uint col2, int fac) | |||||
| { | |||||
| uchar *cp1, *cp2, *cp; | |||||
| int mfac, temp; | |||||
| uint col = 0; | |||||
| if (fac == 0) { | |||||
| return col1; | |||||
| } | |||||
| mfac = 255 - fac; | |||||
| cp1 = (uchar *)&col1; | |||||
| cp2 = (uchar *)&col2; | |||||
| cp = (uchar *)&col; | |||||
| int i = 0; | |||||
| for (i = 0; i < 4; i++) { | |||||
| if (cp1[i] > 127) { | |||||
| temp = 255 - ((255 - 2 * (cp1[i] - 127)) * (255 - cp2[i]) / 255); | |||||
| } | |||||
| else { | |||||
| temp = (2 * cp2[i] * cp1[i]) >> 8; | |||||
| } | |||||
| cp[i] = min_ii((mfac * cp1[i] + temp * fac) / 255, 255); | |||||
| } | |||||
| return col; | |||||
| } | |||||
| BLI_INLINE uint mcol_softlight( | |||||
| uint col1, uint col2, int fac) | |||||
| { | |||||
| uchar *cp1, *cp2, *cp; | |||||
| int mfac, temp; | |||||
| uint col = 0; | |||||
| if (fac == 0) { | |||||
| return col1; | |||||
| } | |||||
| mfac = 255 - fac; | |||||
| cp1 = (uchar *)&col1; | |||||
| cp2 = (uchar *)&col2; | |||||
| cp = (uchar *)&col; | |||||
| int i = 0; | |||||
| for (i = 0; i < 4; i++) { | |||||
| if (cp1[i] < 127) { | |||||
| temp = ((2 * ((cp2[i] / 2) + 64)) * cp1[i]) / 255; | |||||
| } | |||||
| else { | |||||
| temp = 255 - (2 * (255 - ((cp2[i] / 2) + 64)) * (255 - cp1[i]) / 255); | |||||
| } | |||||
| cp[i] = (temp * fac + cp1[i] * mfac) / 255; | |||||
| } | |||||
| return col; | |||||
| } | |||||
| BLI_INLINE uint mcol_exclusion( | |||||
| uint col1, uint col2, int fac) | |||||
| { | |||||
| uchar *cp1, *cp2, *cp; | |||||
| int mfac, temp; | |||||
| uint col = 0; | |||||
| if (fac == 0) { | |||||
| return col1; | |||||
| } | |||||
| mfac = 255 - fac; | |||||
| cp1 = (uchar *)&col1; | |||||
| cp2 = (uchar *)&col2; | |||||
| cp = (uchar *)&col; | |||||
| int i = 0; | |||||
| for (i = 0; i < 4; i++) { | |||||
| temp = 127 - ((2 * (cp1[i] - 127) * (cp2[i] - 127)) / 255); | |||||
| cp[i] = (temp * fac + cp1[i] * mfac) / 255; | |||||
| } | |||||
| return col; | |||||
| } | |||||
| BLI_INLINE uint mcol_luminosity( | |||||
| uint col1, uint col2, int fac) | |||||
| { | |||||
| uchar *cp1, *cp2, *cp; | |||||
| int mfac; | |||||
| uint col = 0; | |||||
| if (fac == 0) { | |||||
| return col1; | |||||
| } | |||||
| mfac = 255 - fac; | |||||
| cp1 = (uchar *)&col1; | |||||
| cp2 = (uchar *)&col2; | |||||
| cp = (uchar *)&col; | |||||
| float h1, s1, v1; | |||||
| float h2, s2, v2; | |||||
| float r, g, b; | |||||
| rgb_to_hsv(cp1[0] / 255.0f, cp1[1] / 255.0f, cp1[2] / 255.0f, &h1, &s1, &v1); | |||||
| rgb_to_hsv(cp2[0] / 255.0f, cp2[1] / 255.0f, cp2[2] / 255.0f, &h2, &s2, &v2); | |||||
| v1 = v2; | |||||
| hsv_to_rgb(h1, s1, v1, &r, &g, &b); | |||||
| cp[0] = ((int)(r * 255.0f) * fac + mfac * cp1[0]) / 255; | |||||
| cp[1] = ((int)(g * 255.0f) * fac + mfac * cp1[1]) / 255; | |||||
| cp[2] = ((int)(b * 255.0f) * fac + mfac * cp1[2]) / 255; | |||||
| cp[3] = ((int)(cp2[3]) * fac + mfac * cp1[3]) / 255; | |||||
| return col; | |||||
| } | |||||
| BLI_INLINE uint mcol_saturation( | |||||
| uint col1, uint col2, int fac) | |||||
| { | |||||
| uchar *cp1, *cp2, *cp; | |||||
| int mfac; | |||||
| uint col = 0; | |||||
mont29: luminocity -> typo? or intended? | |||||
| if (fac == 0) { | |||||
| return col1; | |||||
| } | |||||
| mfac = 255 - fac; | |||||
| cp1 = (uchar *)&col1; | |||||
| cp2 = (uchar *)&col2; | |||||
| cp = (uchar *)&col; | |||||
| float h1, s1, v1; | |||||
| float h2, s2, v2; | |||||
| float r, g, b; | |||||
| rgb_to_hsv(cp1[0] / 255.0f, cp1[1] / 255.0f, cp1[2] / 255.0f, &h1, &s1, &v1); | |||||
| rgb_to_hsv(cp2[0] / 255.0f, cp2[1] / 255.0f, cp2[2] / 255.0f, &h2, &s2, &v2); | |||||
| if (s1 > EPS_SATURATION) { | |||||
| s1 = s2; | |||||
| } | |||||
| hsv_to_rgb(h1, s1, v1, &r, &g, &b); | |||||
| cp[0] = ((int)(r * 255.0f) * fac + mfac * cp1[0]) / 255; | |||||
| cp[1] = ((int)(g * 255.0f) * fac + mfac * cp1[1]) / 255; | |||||
| cp[2] = ((int)(b * 255.0f) * fac + mfac * cp1[2]) / 255; | |||||
| return col; | |||||
| } | |||||
| BLI_INLINE uint mcol_hue( | |||||
| uint col1, uint col2, int fac) | |||||
| { | |||||
| uchar *cp1, *cp2, *cp; | |||||
| int mfac; | |||||
| uint col = 0; | |||||
| if (fac == 0) { | |||||
| return col1; | |||||
| } | |||||
| mfac = 255 - fac; | |||||
| cp1 = (uchar *)&col1; | |||||
| cp2 = (uchar *)&col2; | |||||
| cp = (uchar *)&col; | |||||
| float h1, s1, v1; | |||||
| float h2, s2, v2; | |||||
| float r, g, b; | |||||
| rgb_to_hsv(cp1[0] / 255.0f, cp1[1] / 255.0f, cp1[2] / 255.0f, &h1, &s1, &v1); | |||||
| rgb_to_hsv(cp2[0] / 255.0f, cp2[1] / 255.0f, cp2[2] / 255.0f, &h2, &s2, &v2); | |||||
| h1 = h2; | |||||
| hsv_to_rgb(h1, s1, v1, &r, &g, &b); | |||||
| cp[0] = ((int)(r * 255.0f) * fac + mfac * cp1[0]) / 255; | |||||
| cp[1] = ((int)(g * 255.0f) * fac + mfac * cp1[1]) / 255; | |||||
| cp[2] = ((int)(b * 255.0f) * fac + mfac * cp1[2]) / 255; | |||||
| cp[3] = ((int)(cp2[3]) * fac + mfac * cp1[3]) / 255; | |||||
| return col; | |||||
| } | |||||
| BLI_INLINE uint mcol_alpha_add( | |||||
| uint col1, int fac) | |||||
| { | |||||
| uchar *cp1, *cp; | |||||
| int temp; | |||||
| uint col = 0; | |||||
| if (fac == 0) { | |||||
| return col1; | |||||
| } | |||||
| cp1 = (uchar *)&col1; | |||||
| cp = (uchar *)&col; | |||||
| temp = cp1[3] + fac; | |||||
| cp[3] = (temp > 254) ? 255 : temp; | |||||
| return col; | |||||
| } | |||||
| BLI_INLINE uint mcol_alpha_sub( | |||||
| uint col1, int fac) | |||||
| { | |||||
| uchar *cp1, *cp; | |||||
| int temp; | |||||
| uint col = 0; | |||||
| if (fac == 0) { | |||||
| return col1; | |||||
| } | |||||
| cp1 = (uchar *)&col1; | |||||
| cp = (uchar *)&col; | |||||
| temp = cp1[3] - fac; | |||||
| cp[3] = temp < 0 ? 0 : temp; | |||||
| return col; | return col; | ||||
| } | } | ||||
| /* wpaint has 'wpaint_blend_tool' */ | /* wpaint has 'wpaint_blend_tool' */ | ||||
| static uint vpaint_blend_tool(const int tool, const uint col, | static uint vpaint_blend_tool( | ||||
| const int tool, const uint col, | |||||
| const uint paintcol, const int alpha_i) | const uint paintcol, const int alpha_i) | ||||
| { | { | ||||
| switch (tool) { | switch (tool) { | ||||
| case PAINT_BLEND_MIX: | case PAINT_BLEND_MIX: | ||||
| case PAINT_BLEND_BLUR: return mcol_blend(col, paintcol, alpha_i); | case PAINT_BLEND_BLUR: return mcol_blend(col, paintcol, alpha_i); | ||||
| case PAINT_BLEND_AVERAGE: return mcol_blend(col, paintcol, alpha_i); | case PAINT_BLEND_AVERAGE: return mcol_blend(col, paintcol, alpha_i); | ||||
| case PAINT_BLEND_SMEAR: return mcol_blend(col, paintcol, alpha_i); | case PAINT_BLEND_SMEAR: return mcol_blend(col, paintcol, alpha_i); | ||||
| case PAINT_BLEND_ADD: return mcol_add(col, paintcol, alpha_i); | case PAINT_BLEND_ADD: return mcol_add(col, paintcol, alpha_i); | ||||
| case PAINT_BLEND_SUB: return mcol_sub(col, paintcol, alpha_i); | case PAINT_BLEND_SUB: return mcol_sub(col, paintcol, alpha_i); | ||||
| case PAINT_BLEND_MUL: return mcol_mul(col, paintcol, alpha_i); | case PAINT_BLEND_MUL: return mcol_mul(col, paintcol, alpha_i); | ||||
| case PAINT_BLEND_LIGHTEN: return mcol_lighten(col, paintcol, alpha_i); | case PAINT_BLEND_LIGHTEN: return mcol_lighten(col, paintcol, alpha_i); | ||||
| case PAINT_BLEND_DARKEN: return mcol_darken(col, paintcol, alpha_i); | case PAINT_BLEND_DARKEN: return mcol_darken(col, paintcol, alpha_i); | ||||
| case PAINT_BLEND_COLORDODGE: return mcol_colordodge(col, paintcol, alpha_i); | |||||
| case PAINT_BLEND_DIFFERENCE: return mcol_difference(col, paintcol, alpha_i); | |||||
| case PAINT_BLEND_SCREEN: return mcol_screen(col, paintcol, alpha_i); | |||||
| case PAINT_BLEND_HARDLIGHT: return mcol_hardlight(col, paintcol, alpha_i); | |||||
| case PAINT_BLEND_OVERLAY: return mcol_overlay(col, paintcol, alpha_i); | |||||
| case PAINT_BLEND_SOFTLIGHT: return mcol_softlight(col, paintcol, alpha_i); | |||||
| case PAINT_BLEND_EXCLUSION: return mcol_exclusion(col, paintcol, alpha_i); | |||||
| case PAINT_BLEND_LUMINOCITY: return mcol_luminosity(col, paintcol, alpha_i); | |||||
| case PAINT_BLEND_SATURATION: return mcol_saturation(col, paintcol, alpha_i); | |||||
| case PAINT_BLEND_HUE: return mcol_hue(col, paintcol, alpha_i); | |||||
| /* non-color */ | |||||
| case PAINT_BLEND_ALPHA_SUB: return mcol_alpha_sub(col, alpha_i); | |||||
| case PAINT_BLEND_ALPHA_ADD: return mcol_alpha_add(col, alpha_i); | |||||
| default: | default: | ||||
| BLI_assert(0); | BLI_assert(0); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| } | } | ||||
| /* wpaint has 'wpaint_blend' */ | /* wpaint has 'wpaint_blend' */ | ||||
| static uint vpaint_blend( | static uint vpaint_blend( | ||||
| VPaint *vp, uint col, uint colorig, | VPaint *vp, uint color_curr, uint color_orig, | ||||
| const uint paintcol, const int alpha_i, | uint color_paint, const int alpha_i, | ||||
| /* pre scaled from [0-1] --> [0-255] */ | /* pre scaled from [0-1] --> [0-255] */ | ||||
| const int brush_alpha_value_i) | const int brush_alpha_value_i) | ||||
| { | { | ||||
| Brush *brush = BKE_paint_brush(&vp->paint); | Brush *brush = BKE_paint_brush(&vp->paint); | ||||
| const int tool = brush->vertexpaint_tool; | const int tool = brush->vertexpaint_tool; | ||||
| col = vpaint_blend_tool(tool, col, paintcol, alpha_i); | uint color_blend = vpaint_blend_tool(tool, color_curr, color_paint, alpha_i); | ||||
| /* if no spray, clip color adding with colorig & orig alpha */ | /* if no spray, clip color adding with colorig & orig alpha */ | ||||
| if ((vp->flag & VP_SPRAY) == 0) { | if ((vp->flag & VP_SPRAY) == 0) { | ||||
| uint testcol, a; | uint color_test, a; | ||||
| char *cp, *ct, *co; | char *cp, *ct, *co; | ||||
| testcol = vpaint_blend_tool(tool, colorig, paintcol, brush_alpha_value_i); | color_test = vpaint_blend_tool(tool, color_orig, color_paint, brush_alpha_value_i); | ||||
| cp = (char *)&col; | cp = (char *)&color_blend; | ||||
| ct = (char *)&testcol; | ct = (char *)&color_test; | ||||
| co = (char *)&colorig; | co = (char *)&color_orig; | ||||
| for (a = 0; a < 4; a++) { | for (a = 0; a < 4; a++) { | ||||
| if (ct[a] < co[a]) { | if (ct[a] < co[a]) { | ||||
| if (cp[a] < ct[a]) cp[a] = ct[a]; | if (cp[a] < ct[a]) cp[a] = ct[a]; | ||||
| else if (cp[a] > co[a]) cp[a] = co[a]; | else if (cp[a] > co[a]) cp[a] = co[a]; | ||||
| } | } | ||||
| else { | else { | ||||
| if (cp[a] < co[a]) cp[a] = co[a]; | if (cp[a] < co[a]) cp[a] = co[a]; | ||||
| else if (cp[a] > ct[a]) cp[a] = ct[a]; | else if (cp[a] > ct[a]) cp[a] = ct[a]; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return col; | if ((brush->flag & BRUSH_LOCK_ALPHA) && | ||||
| !ELEM(tool, PAINT_BLEND_ALPHA_SUB, PAINT_BLEND_ALPHA_ADD)) | |||||
| { | |||||
| char *cp, *cc; | |||||
| cp = (char *)&color_blend; | |||||
| cc = (char *)&color_curr; | |||||
| cp[3] = cc[3]; | |||||
| } | |||||
| return color_blend; | |||||
| } | } | ||||
| /* whats _dl mean? */ | /* whats _dl mean? */ | ||||
| static float calc_vp_strength_col_dl( | static float calc_vp_strength_col_dl( | ||||
| VPaint *vp, const ViewContext *vc, const float co[3], | VPaint *vp, const ViewContext *vc, const float co[3], | ||||
| const float mval[2], const float brush_size_pressure, float rgba[4]) | const float mval[2], const float brush_size_pressure, float rgba[4]) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 133 Lines • ▼ Show 20 Lines | switch (tool) { | ||||
| case PAINT_BLEND_SUB: | case PAINT_BLEND_SUB: | ||||
| tool = PAINT_BLEND_ADD; break; | tool = PAINT_BLEND_ADD; break; | ||||
| case PAINT_BLEND_LIGHTEN: | case PAINT_BLEND_LIGHTEN: | ||||
| tool = PAINT_BLEND_DARKEN; break; | tool = PAINT_BLEND_DARKEN; break; | ||||
| case PAINT_BLEND_DARKEN: | case PAINT_BLEND_DARKEN: | ||||
| tool = PAINT_BLEND_LIGHTEN; break; | tool = PAINT_BLEND_LIGHTEN; break; | ||||
| } | } | ||||
| } | } | ||||
| weight = wpaint_blend_tool(tool, weight, paintval, alpha); | weight = wpaint_blend_tool(tool, weight, paintval, alpha); | ||||
| CLAMP(weight, 0.0f, 1.0f); | CLAMP(weight, 0.0f, 1.0f); | ||||
| return weight; | return weight; | ||||
| } | } | ||||
| /* ----------------------------------------------------- */ | /* ----------------------------------------------------- */ | ||||
| /* sets wp->weight to the closest weight value to vertex */ | /* sets wp->weight to the closest weight value to vertex */ | ||||
| /* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */ | /* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */ | ||||
| ▲ Show 20 Lines • Show All 475 Lines • ▼ Show 20 Lines | typedef struct WeightPaintInfo { | ||||
| /* both must add up to 'defbase_tot' */ | /* both must add up to 'defbase_tot' */ | ||||
| int defbase_tot_sel; | int defbase_tot_sel; | ||||
| int defbase_tot_unsel; | int defbase_tot_unsel; | ||||
| struct WeightPaintGroupData active, mirror; | struct WeightPaintGroupData active, mirror; | ||||
| const bool *lock_flags; /* boolean array for locked bones, | const bool *lock_flags; /* boolean array for locked bones, | ||||
| * length of defbase_tot */ | * length of defbase_tot */ | ||||
| const bool *defbase_sel; /* boolean array for selected bones, | const bool *defbase_sel; /* boolean array for selected bones, | ||||
| * length of defbase_tot, cant be const because of how its passed */ | * length of defbase_tot, cant be const because of how its passed */ | ||||
| const bool *vgroup_validmap; /* same as WeightPaintData.vgroup_validmap, | const bool *vgroup_validmap; /* same as WeightPaintData.vgroup_validmap, | ||||
| * only added here for convenience */ | * only added here for convenience */ | ||||
| bool do_flip; | bool do_flip; | ||||
| bool do_multipaint; | bool do_multipaint; | ||||
| bool do_auto_normalize; | bool do_auto_normalize; | ||||
| float brush_alpha_value; /* result of BKE_brush_alpha_get() */ | float brush_alpha_value; /* result of BKE_brush_alpha_get() */ | ||||
| } WeightPaintInfo; | } WeightPaintInfo; | ||||
| ▲ Show 20 Lines • Show All 292 Lines • ▼ Show 20 Lines | if ((ts->vpaint->flag & VP_SPRAY) == 0) { | ||||
| if (ob->sculpt->mode.vpaint.previous_color == NULL) { | if (ob->sculpt->mode.vpaint.previous_color == NULL) { | ||||
| ob->sculpt->mode.vpaint.previous_color = | ob->sculpt->mode.vpaint.previous_color = | ||||
| MEM_callocN(me->totloop * sizeof(uint), "previous_color"); | MEM_callocN(me->totloop * sizeof(uint), "previous_color"); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| MEM_SAFE_FREE(ob->sculpt->mode.vpaint.previous_color); | MEM_SAFE_FREE(ob->sculpt->mode.vpaint.previous_color); | ||||
| } | } | ||||
| /* TODO: when to alloc? */ | |||||
| if (ob->sculpt->mode.vpaint.previous_accum == NULL) { | |||||
| ob->sculpt->mode.vpaint.previous_accum = | |||||
| MEM_callocN(me->totloop * sizeof(uint), "previous_color"); | |||||
| } | |||||
| } | } | ||||
| else if (ob->mode == OB_MODE_WEIGHT_PAINT) { | else if (ob->mode == OB_MODE_WEIGHT_PAINT) { | ||||
| if ((ts->wpaint->flag & VP_SPRAY) == 0) { | if ((ts->wpaint->flag & VP_SPRAY) == 0) { | ||||
| if (ob->sculpt->mode.wpaint.alpha_weight == NULL) { | if (ob->sculpt->mode.wpaint.alpha_weight == NULL) { | ||||
| ob->sculpt->mode.wpaint.alpha_weight = | ob->sculpt->mode.wpaint.alpha_weight = | ||||
| MEM_callocN(me->totvert * sizeof(float), "alpha_weight"); | MEM_callocN(me->totvert * sizeof(float), "alpha_weight"); | ||||
| } | } | ||||
| if (ob->sculpt->mode.wpaint.previous_weight == NULL) { | if (ob->sculpt->mode.wpaint.previous_weight == NULL) { | ||||
| Show All 10 Lines | |||||
| } | } | ||||
| /* *************** set wpaint operator ****************** */ | /* *************** set wpaint operator ****************** */ | ||||
| /** | /** | ||||
| * \note Keep in sync with #vpaint_mode_toggle_exec | * \note Keep in sync with #vpaint_mode_toggle_exec | ||||
| */ | */ | ||||
| static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op) | static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| Object *ob = CTX_data_active_object(C); | Object *ob = CTX_data_active_object(C); | ||||
| const int mode_flag = OB_MODE_WEIGHT_PAINT; | const int mode_flag = OB_MODE_WEIGHT_PAINT; | ||||
| const bool is_mode_set = (ob->mode & mode_flag) != 0; | const bool is_mode_set = (ob->mode & mode_flag) != 0; | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| VPaint *wp = scene->toolsettings->wpaint; | VPaint *wp = scene->toolsettings->wpaint; | ||||
| Mesh *me; | Mesh *me; | ||||
| if (!is_mode_set) { | if (!is_mode_set) { | ||||
| ▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | else { | ||||
| ED_vgroup_sync_from_pose(ob); | ED_vgroup_sync_from_pose(ob); | ||||
| /* Create vertex/weight paint mode session data */ | /* Create vertex/weight paint mode session data */ | ||||
| if (ob->sculpt) { | if (ob->sculpt) { | ||||
| BKE_sculptsession_free(ob); | BKE_sculptsession_free(ob); | ||||
| } | } | ||||
| vertex_paint_init_session(scene, ob); | vertex_paint_init_session(scene, ob); | ||||
| } | } | ||||
| /* Weightpaint works by overriding colors in mesh, | /* Weightpaint works by overriding colors in mesh, | ||||
| * so need to make sure we recalc on enter and | * so need to make sure we recalc on enter and | ||||
| * exit (exit needs doing regardless because we | * exit (exit needs doing regardless because we | ||||
| * should redeform). | * should redeform). | ||||
| */ | */ | ||||
| DAG_id_tag_update(&me->id, 0); | DAG_id_tag_update(&me->id, 0); | ||||
| WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); | WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); | ||||
| Show All 11 Lines | if (!ob->data || ID_IS_LINKED_DATABLOCK(ob->data)) | ||||
| return 0; | return 0; | ||||
| if (CTX_data_edit_object(C)) | if (CTX_data_edit_object(C)) | ||||
| return 0; | return 0; | ||||
| return 1; | return 1; | ||||
| } | } | ||||
| void PAINT_OT_weight_paint_toggle(wmOperatorType *ot) | void PAINT_OT_weight_paint_toggle(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Weight Paint Mode"; | ot->name = "Weight Paint Mode"; | ||||
| ot->idname = "PAINT_OT_weight_paint_toggle"; | ot->idname = "PAINT_OT_weight_paint_toggle"; | ||||
| ot->description = "Toggle weight paint mode in 3D view"; | ot->description = "Toggle weight paint mode in 3D view"; | ||||
| /* api callbacks */ | /* api callbacks */ | ||||
| ot->exec = wpaint_mode_toggle_exec; | ot->exec = wpaint_mode_toggle_exec; | ||||
| ot->poll = paint_poll_test; | ot->poll = paint_poll_test; | ||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| } | } | ||||
| /* ************ weight paint operator ********** */ | /* ************ weight paint operator ********** */ | ||||
| enum eWPaintFlag { | enum eWPaintFlag { | ||||
| WPAINT_ENSURE_MIRROR = (1 << 0), | WPAINT_ENSURE_MIRROR = (1 << 0), | ||||
| }; | }; | ||||
| ▲ Show 20 Lines • Show All 415 Lines • ▼ Show 20 Lines | static void calc_area_normal( | ||||
| float r_area_no[3]) | float r_area_no[3]) | ||||
| { | { | ||||
| /* 0=towards view, 1=flipped */ | /* 0=towards view, 1=flipped */ | ||||
| float area_nos[2][3] = {{0.0f}}; | float area_nos[2][3] = {{0.0f}}; | ||||
| int count[2] = {0}; | int count[2] = {0}; | ||||
| SculptThreadedTaskData data = { | SculptThreadedTaskData data = { | ||||
| .vp = vp, .ob = ob, .nodes = nodes, .totnode = totnode, | .vp = vp, .ob = ob, .nodes = nodes, .totnode = totnode, | ||||
| .area_cos = NULL, .area_nos = area_nos, .count = count, | .area_cos = NULL, .area_nos = area_nos, .count = count, | ||||
| }; | }; | ||||
| BLI_mutex_init(&data.mutex); | BLI_mutex_init(&data.mutex); | ||||
| BLI_task_parallel_range( | BLI_task_parallel_range( | ||||
| 0, totnode, &data, calc_area_normal_and_center_task_cb, true); | 0, totnode, &data, calc_area_normal_and_center_task_cb, true); | ||||
| BLI_mutex_end(&data.mutex); | BLI_mutex_end(&data.mutex); | ||||
| ▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | *r_brush_size_pressure = | ||||
| (BKE_brush_use_size_pressure(scene, brush) ? ss->cache->pressure : 1.0f); | (BKE_brush_use_size_pressure(scene, brush) ? ss->cache->pressure : 1.0f); | ||||
| *r_brush_alpha_value = | *r_brush_alpha_value = | ||||
| BKE_brush_alpha_get(scene, brush); | BKE_brush_alpha_get(scene, brush); | ||||
| *r_brush_alpha_pressure = | *r_brush_alpha_pressure = | ||||
| *r_brush_alpha_value * | *r_brush_alpha_value * | ||||
| (BKE_brush_use_alpha_pressure(scene, brush) ? ss->cache->pressure : 1.0f); | (BKE_brush_use_alpha_pressure(scene, brush) ? ss->cache->pressure : 1.0f); | ||||
| } | } | ||||
| static bool is_non_occluded( | |||||
| StrokeCache *cache, PBVHVertexIter vd, const float radius, const bool do_occlude, float *r_dist) | |||||
| { | |||||
| if (cache->vc->ar && !do_occlude) { | |||||
| float sco[2]; | |||||
| ED_view3d_project_float_v2_m4(cache->vc->ar, vd.co, sco, cache->projection_mat); | |||||
| const float dist_sq = len_squared_v2v2(cache->mouse, sco); | |||||
| *r_dist = sqrtf(dist_sq); | |||||
| if (dist_sq <= SQUARE(radius)) { | |||||
| return true; | |||||
| } | |||||
| } | |||||
| return false; | |||||
Not Done Inline ActionsNote that this is using a cylinder falloff which will not pick up all BVH nodes in the line of sight since it's using nodes in a sphere from the brush center. campbellbarton: Note that this is using a cylinder falloff which will not pick up all BVH nodes in the line of… | |||||
| } | |||||
| static void do_wpaint_brush_blur_task_cb_ex( | static void do_wpaint_brush_blur_task_cb_ex( | ||||
| void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) | void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) | ||||
| { | { | ||||
| SculptThreadedTaskData *data = userdata; | SculptThreadedTaskData *data = userdata; | ||||
| SculptSession *ss = data->ob->sculpt; | SculptSession *ss = data->ob->sculpt; | ||||
| CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); | CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); | ||||
| const struct SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap; | const struct SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap; | ||||
| Brush *brush = data->brush; | Brush *brush = data->brush; | ||||
| StrokeCache *cache = ss->cache; | StrokeCache *cache = ss->cache; | ||||
| Scene *scene = CTX_data_scene(data->C); | Scene *scene = CTX_data_scene(data->C); | ||||
| const float brush_strength = cache->bstrength; | const float brush_strength = cache->bstrength; | ||||
| float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; | float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; | ||||
| get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); | get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); | ||||
| const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; | const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; | ||||
| const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; | const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; | ||||
| const float radius = BKE_brush_size_get(scene, brush); | |||||
| SculptBrushTest test; | SculptBrushTest test; | ||||
| sculpt_brush_test_init(ss, &test); | sculpt_brush_test_init(ss, &test); | ||||
| /* For each vertex */ | /* For each vertex */ | ||||
| PBVHVertexIter vd; | PBVHVertexIter vd; | ||||
| BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) | BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) | ||||
| { | { | ||||
| const bool do_occlude = (data->vp->flag & VP_NO_OCCLUDE) == 0; | |||||
| float dist = 0.0f; | |||||
| const bool non_occlude = is_non_occluded(cache, vd, radius, do_occlude, &dist); | |||||
| /* Test to see if the vertex coordinates are within the spherical brush region. */ | /* Test to see if the vertex coordinates are within the spherical brush region. */ | ||||
| if (sculpt_brush_test_sq(&test, vd.co)) { | if (sculpt_brush_test_sq(&test, vd.co) || non_occlude) { | ||||
| /* For grid based pbvh, take the vert whose loop coopresponds to the current grid. | /* For grid based pbvh, take the vert whose loop coopresponds to the current grid. | ||||
| * Otherwise, take the current vert. */ | * Otherwise, take the current vert. */ | ||||
| const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; | const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; | ||||
| const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; | const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; | ||||
| const char v_flag = data->me->mvert[v_index].flag; | const char v_flag = data->me->mvert[v_index].flag; | ||||
| /* If the vertex is selected */ | /* If the vertex is selected */ | ||||
| if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) { | if (!(use_face_sel || use_vert_sel) || v_flag & SELECT || (non_occlude && !use_vert_sel)) { | ||||
| /* Get the average poly weight */ | /* Get the average poly weight */ | ||||
| int total_hit_loops = 0; | int total_hit_loops = 0; | ||||
| float weight_final = 0.0f; | float weight_final = 0.0f; | ||||
| for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { | for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { | ||||
| const int p_index = gmap->vert_to_poly[v_index].indices[j]; | const int p_index = gmap->vert_to_poly[v_index].indices[j]; | ||||
| const MPoly *mp = &data->me->mpoly[p_index]; | const MPoly *mp = &data->me->mpoly[p_index]; | ||||
| total_hit_loops += mp->totloop; | total_hit_loops += mp->totloop; | ||||
| for (int k = 0; k < mp->totloop; k++) { | for (int k = 0; k < mp->totloop; k++) { | ||||
| const int l_index = mp->loopstart + k; | const int l_index = mp->loopstart + k; | ||||
| const MLoop *ml = &data->me->mloop[l_index]; | const MLoop *ml = &data->me->mloop[l_index]; | ||||
| const MDeformVert *dv = &data->me->dvert[ml->v]; | const MDeformVert *dv = &data->me->dvert[ml->v]; | ||||
| weight_final += defvert_find_weight(dv, data->wpi->active.index); | weight_final += defvert_find_weight(dv, data->wpi->active.index); | ||||
| } | } | ||||
| } | } | ||||
| /* Apply the weight to the vertex. */ | /* Apply the weight to the vertex. */ | ||||
| if (total_hit_loops != 0) { | if (total_hit_loops != 0) { | ||||
| const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; | const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; | ||||
| if (view_dot > 0.0f) { | if (view_dot > 0.0f) { | ||||
| const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius); | const float brush_fade = BKE_brush_curve_strength(brush, dist, radius); | ||||
| const float final_alpha = | const float final_alpha = | ||||
| view_dot * brush_fade * brush_strength * | view_dot * brush_fade * brush_strength * | ||||
| grid_alpha * brush_alpha_pressure; | grid_alpha * brush_alpha_pressure; | ||||
| weight_final /= total_hit_loops; | weight_final /= total_hit_loops; | ||||
| /* Only paint visable verts */ | /* Only paint visable verts */ | ||||
| do_weight_paint_vertex( | do_weight_paint_vertex( | ||||
| data->vp, data->ob, data->wpi, | data->vp, data->ob, data->wpi, | ||||
| Show All 18 Lines | static void do_wpaint_brush_smear_task_cb_ex( | ||||
| Scene *scene = CTX_data_scene(data->C); | Scene *scene = CTX_data_scene(data->C); | ||||
| StrokeCache *cache = ss->cache; | StrokeCache *cache = ss->cache; | ||||
| const float brush_strength = cache->bstrength; | const float brush_strength = cache->bstrength; | ||||
| float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; | float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; | ||||
| get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); | get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); | ||||
| const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; | const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; | ||||
| const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; | const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; | ||||
| float brush_dir[3]; | float brush_dir[3]; | ||||
| const float radius = BKE_brush_size_get(scene, brush); | |||||
| sub_v3_v3v3(brush_dir, cache->location, cache->last_location); | sub_v3_v3v3(brush_dir, cache->location, cache->last_location); | ||||
| if (normalize_v3(brush_dir) != 0.0f) { | if (normalize_v3(brush_dir) != 0.0f) { | ||||
| SculptBrushTest test; | SculptBrushTest test; | ||||
| sculpt_brush_test_init(ss, &test); | sculpt_brush_test_init(ss, &test); | ||||
| /* For each vertex */ | /* For each vertex */ | ||||
| PBVHVertexIter vd; | PBVHVertexIter vd; | ||||
| BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) | BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) | ||||
| { | { | ||||
| float dist = 0.0f; | |||||
| const bool do_occlude = (data->vp->flag & VP_NO_OCCLUDE) == 0; | |||||
| const bool non_occlude = is_non_occluded(cache, vd, radius, do_occlude, &dist); | |||||
| /* Test to see if the vertex coordinates are within the spherical brush region. */ | /* Test to see if the vertex coordinates are within the spherical brush region. */ | ||||
| if (sculpt_brush_test_fast(&test, vd.co)) { | if (sculpt_brush_test_fast(&test, vd.co) || non_occlude) { | ||||
| const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; | const float view_dot = (vd.no && !non_occlude) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; | ||||
| if (view_dot > 0.0f) { | if (view_dot > 0.0f) { | ||||
| bool do_color = false; | bool do_color = false; | ||||
| /* For grid based pbvh, take the vert whose loop cooresponds to the current grid. | /* For grid based pbvh, take the vert whose loop cooresponds to the current grid. | ||||
| * Otherwise, take the current vert. */ | * Otherwise, take the current vert. */ | ||||
| const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; | const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; | ||||
| const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; | const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; | ||||
| const MVert *mv_curr = &data->me->mvert[v_index]; | const MVert *mv_curr = &data->me->mvert[v_index]; | ||||
| const char v_flag = data->me->mvert[v_index].flag; | const char v_flag = data->me->mvert[v_index].flag; | ||||
| /* If the vertex is selected */ | /* If the vertex is selected */ | ||||
| if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) { | if (!(use_face_sel || use_vert_sel) || v_flag & SELECT || (non_occlude && !use_vert_sel)) { | ||||
| /* Minimum dot product between brush direction and current | /* Minimum dot product between brush direction and current | ||||
| * to neighbor direction is 0.0, meaning orthogonal. */ | * to neighbor direction is 0.0, meaning orthogonal. */ | ||||
| float stroke_dot_max = 0.0f; | float stroke_dot_max = 0.0f; | ||||
| /* Get the color of the loop in the opposite direction of the brush movement | /* Get the color of the loop in the opposite direction of the brush movement | ||||
| * (this callback is specifically for smear.) */ | * (this callback is specifically for smear.) */ | ||||
| float weight_final = 0.0; | float weight_final = 0.0; | ||||
| for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { | for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { | ||||
| Show All 17 Lines | BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) | ||||
| MDeformVert *dv = &data->me->dvert[v_other_index]; | MDeformVert *dv = &data->me->dvert[v_other_index]; | ||||
| weight_final = defvert_find_weight(dv, data->wpi->active.index); | weight_final = defvert_find_weight(dv, data->wpi->active.index); | ||||
| do_color = true; | do_color = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Apply weight to vertex */ | /* Apply weight to vertex */ | ||||
| if (do_color) { | if (do_color) { | ||||
| const float brush_fade = BKE_brush_curve_strength(brush, test.dist, cache->radius); | const float brush_fade = BKE_brush_curve_strength(brush, dist, radius); | ||||
| const float final_alpha = | const float final_alpha = | ||||
| view_dot * brush_fade * brush_strength * | view_dot * brush_fade * brush_strength * | ||||
| grid_alpha * brush_alpha_pressure; | grid_alpha * brush_alpha_pressure; | ||||
| do_weight_paint_vertex( | do_weight_paint_vertex( | ||||
| data->vp, data->ob, data->wpi, | data->vp, data->ob, data->wpi, | ||||
| v_index, final_alpha, (float)weight_final); | v_index, final_alpha, (float)weight_final); | ||||
| } | } | ||||
| } | } | ||||
| Show All 15 Lines | static void do_wpaint_brush_draw_task_cb_ex( | ||||
| Brush *brush = data->brush; | Brush *brush = data->brush; | ||||
| StrokeCache *cache = ss->cache; | StrokeCache *cache = ss->cache; | ||||
| const float brush_strength = cache->bstrength; | const float brush_strength = cache->bstrength; | ||||
| const float paintweight = BKE_brush_weight_get(scene, brush); | const float paintweight = BKE_brush_weight_get(scene, brush); | ||||
| float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; | float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; | ||||
| get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); | get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); | ||||
| const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; | const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; | ||||
| const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; | const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; | ||||
| const float radius = BKE_brush_size_get(scene, brush); | |||||
| SculptBrushTest test; | SculptBrushTest test; | ||||
| sculpt_brush_test_init(ss, &test); | sculpt_brush_test_init(ss, &test); | ||||
| /* For each vertex */ | /* For each vertex */ | ||||
| PBVHVertexIter vd; | PBVHVertexIter vd; | ||||
| BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) | BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) | ||||
| { | { | ||||
| float dist = 0.0f; | |||||
| const bool do_occlude = (data->vp->flag & VP_NO_OCCLUDE) == 0; | |||||
| const bool non_occlude = is_non_occluded(cache, vd, radius, do_occlude, &dist); | |||||
| /* Test to see if the vertex coordinates are within the spherical brush region. */ | /* Test to see if the vertex coordinates are within the spherical brush region. */ | ||||
| if (sculpt_brush_test_sq(&test, vd.co)) { | if (sculpt_brush_test_sq(&test, vd.co) || non_occlude) { | ||||
| /* Note: grids are 1:1 with corners (aka loops). | /* Note: grids are 1:1 with corners (aka loops). | ||||
| * For multires, take the vert whose loop cooresponds to the current grid. | * For multires, take the vert whose loop cooresponds to the current grid. | ||||
| * Otherwise, take the current vert. */ | * Otherwise, take the current vert. */ | ||||
| const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; | const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; | ||||
| const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; | const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; | ||||
| const char v_flag = data->me->mvert[v_index].flag; | const char v_flag = data->me->mvert[v_index].flag; | ||||
| /* If the vertex is selected */ | /* If the vertex is selected */ | ||||
| if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) { | if (!(use_face_sel || use_vert_sel) || v_flag & SELECT || (non_occlude && !use_vert_sel)) { | ||||
| const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; | const float view_dot = (vd.no && !non_occlude) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; | ||||
| if (view_dot > 0.0f) { | if (view_dot > 0.0f) { | ||||
| const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius); | const float brush_fade = BKE_brush_curve_strength(brush, dist, radius); | ||||
| float final_alpha = view_dot * brush_fade * brush_strength * grid_alpha * brush_alpha_pressure; | float final_alpha = view_dot * brush_fade * brush_strength * grid_alpha * brush_alpha_pressure; | ||||
| /* Non-spray logic. */ | /* Non-spray logic. */ | ||||
| if ((data->vp->flag & VP_SPRAY) == 0) { | if ((data->vp->flag & VP_SPRAY) == 0) { | ||||
| /* Only paint if we have greater alpha. */ | /* Only paint if we have greater alpha. */ | ||||
| if (ss->mode.wpaint.alpha_weight[v_index] < final_alpha) { | if (ss->mode.wpaint.alpha_weight[v_index] < final_alpha) { | ||||
| ss->mode.wpaint.alpha_weight[v_index] = final_alpha; | ss->mode.wpaint.alpha_weight[v_index] = final_alpha; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 95 Lines • ▼ Show 20 Lines | |||||
| static void wpaint_paint_leaves( | static void wpaint_paint_leaves( | ||||
| bContext *C, Object *ob, Sculpt *sd, VPaint *vp, struct WPaintData *wpd, WeightPaintInfo *wpi, | bContext *C, Object *ob, Sculpt *sd, VPaint *vp, struct WPaintData *wpd, WeightPaintInfo *wpi, | ||||
| Mesh *me, PBVHNode **nodes, int totnode) | Mesh *me, PBVHNode **nodes, int totnode) | ||||
| { | { | ||||
| Brush *brush = ob->sculpt->cache->brush; | Brush *brush = ob->sculpt->cache->brush; | ||||
| /* threaded loop over nodes */ | /* threaded loop over nodes */ | ||||
| SculptThreadedTaskData data = { | SculptThreadedTaskData data = { | ||||
| .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .wpd = wpd, .wpi = wpi, .me = me, .C = C, | .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .wpd = wpd, .wpi = wpi, .me = me, .C = C, | ||||
| }; | }; | ||||
| switch (brush->vertexpaint_tool) { | switch (brush->vertexpaint_tool) { | ||||
| case PAINT_BLEND_AVERAGE: | case PAINT_BLEND_AVERAGE: | ||||
| calculate_average_weight(&data, nodes, totnode); | calculate_average_weight(&data, nodes, totnode); | ||||
| BLI_task_parallel_range_ex( | BLI_task_parallel_range_ex( | ||||
| 0, totnode, &data, NULL, 0, | 0, totnode, &data, NULL, 0, | ||||
| do_wpaint_brush_draw_task_cb_ex, true, false); | do_wpaint_brush_draw_task_cb_ex, true, false); | ||||
| ▲ Show 20 Lines • Show All 124 Lines • ▼ Show 20 Lines | if (wpd == NULL) { | ||||
| /* XXX: force a redraw here, since even though we can't paint, | /* XXX: force a redraw here, since even though we can't paint, | ||||
| * at least view won't freeze until stroke ends */ | * at least view won't freeze until stroke ends */ | ||||
| ED_region_tag_redraw(CTX_wm_region(C)); | ED_region_tag_redraw(CTX_wm_region(C)); | ||||
| return; | return; | ||||
| } | } | ||||
| vc = &wpd->vc; | vc = &wpd->vc; | ||||
| ob = vc->obact; | ob = vc->obact; | ||||
| view3d_operator_needs_opengl(C); | view3d_operator_needs_opengl(C); | ||||
| ED_view3d_init_mats_rv3d(ob, vc->rv3d); | ED_view3d_init_mats_rv3d(ob, vc->rv3d); | ||||
| /* load projection matrix */ | /* load projection matrix */ | ||||
| mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat); | mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat); | ||||
| /* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */ | /* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */ | ||||
| ▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) | ||||
| } | } | ||||
| ED_region_tag_redraw_partial(vc->ar, &r); | ED_region_tag_redraw_partial(vc->ar, &r); | ||||
| } | } | ||||
| static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) | static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) | ||||
| { | { | ||||
| Object *ob = CTX_data_active_object(C); | Object *ob = CTX_data_active_object(C); | ||||
| struct WPaintData *wpd = paint_stroke_mode_data(stroke); | struct WPaintData *wpd = paint_stroke_mode_data(stroke); | ||||
| if (wpd) { | if (wpd) { | ||||
| ED_vpaint_proj_handle_free(wpd->vp_handle); | ED_vpaint_proj_handle_free(wpd->vp_handle); | ||||
| if (wpd->defbase_sel) | if (wpd->defbase_sel) | ||||
| MEM_freeN((void *)wpd->defbase_sel); | MEM_freeN((void *)wpd->defbase_sel); | ||||
| if (wpd->vgroup_validmap) | if (wpd->vgroup_validmap) | ||||
| MEM_freeN((void *)wpd->vgroup_validmap); | MEM_freeN((void *)wpd->vgroup_validmap); | ||||
| if (wpd->lock_flags) | if (wpd->lock_flags) | ||||
| MEM_freeN((void *)wpd->lock_flags); | MEM_freeN((void *)wpd->lock_flags); | ||||
| if (wpd->active.lock) | if (wpd->active.lock) | ||||
| MEM_freeN((void *)wpd->active.lock); | MEM_freeN((void *)wpd->active.lock); | ||||
| if (wpd->mirror.lock) | if (wpd->mirror.lock) | ||||
| MEM_freeN((void *)wpd->mirror.lock); | MEM_freeN((void *)wpd->mirror.lock); | ||||
| MEM_freeN(wpd); | MEM_freeN(wpd); | ||||
| } | } | ||||
| /* and particles too */ | /* and particles too */ | ||||
| if (ob->particlesystem.first) { | if (ob->particlesystem.first) { | ||||
| ParticleSystem *psys; | ParticleSystem *psys; | ||||
| int i; | int i; | ||||
| for (psys = ob->particlesystem.first; psys; psys = psys->next) { | for (psys = ob->particlesystem.first; psys; psys = psys->next) { | ||||
| for (i = 0; i < PSYS_TOT_VG; i++) { | for (i = 0; i < PSYS_TOT_VG; i++) { | ||||
| if (psys->vgroup[i] == ob->actdef) { | if (psys->vgroup[i] == ob->actdef) { | ||||
| psys->recalc |= PSYS_RECALC_RESET; | psys->recalc |= PSYS_RECALC_RESET; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| Show All 11 Lines | |||||
| static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) | static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| int retval; | int retval; | ||||
| op->customdata = paint_stroke_new( | op->customdata = paint_stroke_new( | ||||
| C, op, sculpt_stroke_get_location, wpaint_stroke_test_start, | C, op, sculpt_stroke_get_location, wpaint_stroke_test_start, | ||||
| wpaint_stroke_update_step, NULL, | wpaint_stroke_update_step, NULL, | ||||
| wpaint_stroke_done, event->type); | wpaint_stroke_done, event->type); | ||||
| if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) { | if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) { | ||||
| paint_stroke_data_free(op); | paint_stroke_data_free(op); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| /* add modal handler */ | /* add modal handler */ | ||||
| WM_event_add_modal_handler(C, op); | WM_event_add_modal_handler(C, op); | ||||
| OPERATOR_RETVAL_CHECK(retval); | OPERATOR_RETVAL_CHECK(retval); | ||||
| BLI_assert(retval == OPERATOR_RUNNING_MODAL); | BLI_assert(retval == OPERATOR_RUNNING_MODAL); | ||||
| return OPERATOR_RUNNING_MODAL; | return OPERATOR_RUNNING_MODAL; | ||||
| } | } | ||||
| static int wpaint_exec(bContext *C, wmOperator *op) | static int wpaint_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| op->customdata = paint_stroke_new( | op->customdata = paint_stroke_new( | ||||
| C, op, sculpt_stroke_get_location, wpaint_stroke_test_start, | C, op, sculpt_stroke_get_location, wpaint_stroke_test_start, | ||||
| wpaint_stroke_update_step, NULL, | wpaint_stroke_update_step, NULL, | ||||
| Show All 13 Lines | if (ob->sculpt->cache) { | ||||
| ob->sculpt->cache = NULL; | ob->sculpt->cache = NULL; | ||||
| } | } | ||||
| paint_stroke_cancel(C, op); | paint_stroke_cancel(C, op); | ||||
| } | } | ||||
| void PAINT_OT_weight_paint(wmOperatorType *ot) | void PAINT_OT_weight_paint(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Weight Paint"; | ot->name = "Weight Paint"; | ||||
| ot->idname = "PAINT_OT_weight_paint"; | ot->idname = "PAINT_OT_weight_paint"; | ||||
| ot->description = "Paint a stroke in the current vertex group's weights"; | ot->description = "Paint a stroke in the current vertex group's weights"; | ||||
| /* api callbacks */ | /* api callbacks */ | ||||
| ot->invoke = wpaint_invoke; | ot->invoke = wpaint_invoke; | ||||
| ot->modal = paint_stroke_modal; | ot->modal = paint_stroke_modal; | ||||
| ot->exec = wpaint_exec; | ot->exec = wpaint_exec; | ||||
| ot->poll = weight_paint_poll; | ot->poll = weight_paint_poll; | ||||
| ot->cancel = wpaint_cancel; | ot->cancel = wpaint_cancel; | ||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; | ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; | ||||
| paint_stroke_operator_properties(ot); | paint_stroke_operator_properties(ot); | ||||
| } | } | ||||
| static int weight_paint_set_exec(bContext *C, wmOperator *op) | static int weight_paint_set_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| struct Scene *scene = CTX_data_scene(C); | struct Scene *scene = CTX_data_scene(C); | ||||
| Object *obact = CTX_data_active_object(C); | Object *obact = CTX_data_active_object(C); | ||||
| ToolSettings *ts = CTX_data_tool_settings(C); | ToolSettings *ts = CTX_data_tool_settings(C); | ||||
| Show All 29 Lines | |||||
| } | } | ||||
| /* ************ set / clear vertex paint mode ********** */ | /* ************ set / clear vertex paint mode ********** */ | ||||
| /** | /** | ||||
| * \note Keep in sync with #wpaint_mode_toggle_exec | * \note Keep in sync with #wpaint_mode_toggle_exec | ||||
| */ | */ | ||||
| static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) | static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| Object *ob = CTX_data_active_object(C); | Object *ob = CTX_data_active_object(C); | ||||
| const int mode_flag = OB_MODE_VERTEX_PAINT; | const int mode_flag = OB_MODE_VERTEX_PAINT; | ||||
| const bool is_mode_set = (ob->mode & mode_flag) != 0; | const bool is_mode_set = (ob->mode & mode_flag) != 0; | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| VPaint *vp = scene->toolsettings->vpaint; | VPaint *vp = scene->toolsettings->vpaint; | ||||
| Mesh *me; | Mesh *me; | ||||
| if (!is_mode_set) { | if (!is_mode_set) { | ||||
| if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { | if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| } | } | ||||
| me = BKE_mesh_from_object(ob); | me = BKE_mesh_from_object(ob); | ||||
| /* toggle: end vpaint */ | /* toggle: end vpaint */ | ||||
| if (is_mode_set) { | if (is_mode_set) { | ||||
| ob->mode &= ~mode_flag; | ob->mode &= ~mode_flag; | ||||
| if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { | if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { | ||||
| BKE_mesh_flush_select_from_polys(me); | BKE_mesh_flush_select_from_polys(me); | ||||
| } | } | ||||
| else if (me->editflag & ME_EDIT_PAINT_VERT_SEL) { | |||||
| BKE_mesh_flush_select_from_verts(me); | |||||
| } | |||||
| /* If the cache is not released by a cancel or a done, free it now. */ | /* If the cache is not released by a cancel or a done, free it now. */ | ||||
| if (ob->sculpt->cache) { | if (ob->sculpt->cache) { | ||||
| sculpt_cache_free(ob->sculpt->cache); | sculpt_cache_free(ob->sculpt->cache); | ||||
| ob->sculpt->cache = NULL; | ob->sculpt->cache = NULL; | ||||
| } | } | ||||
| BKE_sculptsession_free(ob); | BKE_sculptsession_free(ob); | ||||
| paint_cursor_delete_textures(); | paint_cursor_delete_textures(); | ||||
| } | } | ||||
| else { | else { | ||||
| ob->mode |= mode_flag; | ob->mode |= mode_flag; | ||||
| if (me->mloopcol == NULL) { | if (me->mloopcol == NULL) { | ||||
| make_vertexcol(ob); | make_vertexcol(ob); | ||||
| } | } | ||||
| if (vp == NULL) | if (vp == NULL) | ||||
| vp = scene->toolsettings->vpaint = new_vpaint(0); | vp = scene->toolsettings->vpaint = new_vpaint(0); | ||||
| paint_cursor_start(C, vertex_paint_poll); | paint_cursor_start(C, vertex_paint_poll); | ||||
| BKE_paint_init(scene, ePaintVertex, PAINT_CURSOR_VERTEX_PAINT); | BKE_paint_init(scene, ePaintVertex, PAINT_CURSOR_VERTEX_PAINT); | ||||
| /* Create vertex/weight paint mode session data */ | /* Create vertex/weight paint mode session data */ | ||||
| if (ob->sculpt) { | if (ob->sculpt) { | ||||
| if (ob->sculpt->cache) { | if (ob->sculpt->cache) { | ||||
| sculpt_cache_free(ob->sculpt->cache); | sculpt_cache_free(ob->sculpt->cache); | ||||
| ob->sculpt->cache = NULL; | ob->sculpt->cache = NULL; | ||||
| } | } | ||||
| BKE_sculptsession_free(ob); | BKE_sculptsession_free(ob); | ||||
| } | } | ||||
| vertex_paint_init_session(scene, ob); | vertex_paint_init_session(scene, ob); | ||||
| } | } | ||||
| /* update modifier stack for mapping requirements */ | /* update modifier stack for mapping requirements */ | ||||
| DAG_id_tag_update(&me->id, 0); | DAG_id_tag_update(&me->id, 0); | ||||
| WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); | WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot) | void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Vertex Paint Mode"; | ot->name = "Vertex Paint Mode"; | ||||
| ot->idname = "PAINT_OT_vertex_paint_toggle"; | ot->idname = "PAINT_OT_vertex_paint_toggle"; | ||||
| ot->description = "Toggle the vertex paint mode in 3D view"; | ot->description = "Toggle the vertex paint mode in 3D view"; | ||||
| /* api callbacks */ | /* api callbacks */ | ||||
| ot->exec = vpaint_mode_toggle_exec; | ot->exec = vpaint_mode_toggle_exec; | ||||
| ot->poll = paint_poll_test; | ot->poll = paint_poll_test; | ||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| } | } | ||||
| /* ********************** vertex paint operator ******************* */ | /* ********************** vertex paint operator ******************* */ | ||||
| /* Implementation notes: | /* Implementation notes: | ||||
| * | * | ||||
| * Operator->invoke() | * Operator->invoke() | ||||
| * - validate context (add mcol) | * - validate context (add mcol) | ||||
| * - create customdata storage | * - create customdata storage | ||||
| * - call paint once (mouse click) | * - call paint once (mouse click) | ||||
| * - add modal handler | * - add modal handler | ||||
| * | * | ||||
| * Operator->modal() | * Operator->modal() | ||||
| * - for every mousemove, apply vertex paint | * - for every mousemove, apply vertex paint | ||||
| * - exit on mouse release, free customdata | * - exit on mouse release, free customdata | ||||
| * (return OPERATOR_FINISHED also removes handler and operator) | * (return OPERATOR_FINISHED also removes handler and operator) | ||||
| * | * | ||||
| * For future: | * For future: | ||||
| * - implement a stroke event (or mousemove with past positons) | * - implement a stroke event (or mousemove with past positons) | ||||
| Show All 37 Lines | static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const float mouse[2]) | ||||
| Mesh *me; | Mesh *me; | ||||
| float mat[4][4], imat[4][4]; | float mat[4][4], imat[4][4]; | ||||
| SculptSession *ss = ob->sculpt; | SculptSession *ss = ob->sculpt; | ||||
| /* context checks could be a poll() */ | /* context checks could be a poll() */ | ||||
| me = BKE_mesh_from_object(ob); | me = BKE_mesh_from_object(ob); | ||||
| if (me == NULL || me->totpoly == 0) | if (me == NULL || me->totpoly == 0) | ||||
| return false; | return false; | ||||
| if (me->mloopcol == NULL) | if (me->mloopcol == NULL) | ||||
| make_vertexcol(ob); | make_vertexcol(ob); | ||||
| if (me->mloopcol == NULL) | if (me->mloopcol == NULL) | ||||
| return false; | return false; | ||||
| /* make mode data storage */ | /* make mode data storage */ | ||||
| vpd = MEM_callocN(sizeof(*vpd), "VPaintData"); | vpd = MEM_callocN(sizeof(*vpd), "VPaintData"); | ||||
| paint_stroke_set_mode_data(stroke, vpd); | paint_stroke_set_mode_data(stroke, vpd); | ||||
| view3d_set_viewcontext(C, &vpd->vc); | view3d_set_viewcontext(C, &vpd->vc); | ||||
| vpd->paintcol = vpaint_get_current_col(scene, vp); | vpd->paintcol = vpaint_get_current_col(scene, vp); | ||||
| vpd->is_texbrush = !(brush->vertexpaint_tool == PAINT_BLEND_BLUR) && | vpd->is_texbrush = !(brush->vertexpaint_tool == PAINT_BLEND_BLUR) && | ||||
| brush->mtex.tex; | brush->mtex.tex; | ||||
| /* are we painting onto a modified mesh?, | /* are we painting onto a modified mesh?, | ||||
| * if not we can skip face map trickiness */ | * if not we can skip face map trickiness */ | ||||
| if (vertex_paint_use_fast_update_check(ob)) { | if (vertex_paint_use_fast_update_check(ob)) { | ||||
| ▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | static void do_vpaint_brush_calc_average_color_cb_ex( | ||||
| CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); | CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); | ||||
| const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; | const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; | ||||
| StrokeCache *cache = ss->cache; | StrokeCache *cache = ss->cache; | ||||
| uint *lcol = data->lcol; | uint *lcol = data->lcol; | ||||
| char *col; | char *col; | ||||
| const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; | const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; | ||||
| const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; | |||||
| struct VPaintAverageAccum *accum = (struct VPaintAverageAccum *)data->custom_data + n; | struct VPaintAverageAccum *accum = (struct VPaintAverageAccum *)data->custom_data + n; | ||||
| accum->len = 0; | accum->len = 0; | ||||
| memset(accum->value, 0, sizeof(accum->value)); | memset(accum->value, 0, sizeof(accum->value)); | ||||
| SculptBrushTest test; | SculptBrushTest test; | ||||
| sculpt_brush_test_init(ss, &test); | sculpt_brush_test_init(ss, &test); | ||||
| /* For each vertex */ | /* For each vertex */ | ||||
| PBVHVertexIter vd; | PBVHVertexIter vd; | ||||
| BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) | BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) | ||||
| { | { | ||||
| /* Test to see if the vertex coordinates are within the spherical brush region. */ | /* Test to see if the vertex coordinates are within the spherical brush region. */ | ||||
| if (sculpt_brush_test_fast(&test, vd.co)) { | if (sculpt_brush_test_fast(&test, vd.co)) { | ||||
| const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; | const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; | ||||
| if (BKE_brush_curve_strength(data->brush, test.dist, cache->radius) > 0.0) { | if (BKE_brush_curve_strength(data->brush, test.dist, cache->radius) > 0.0) { | ||||
| /* If the vertex is selected for painting. */ | /* If the vertex is selected for painting. */ | ||||
| const MVert *mv = &data->me->mvert[v_index]; | const MVert *mv = &data->me->mvert[v_index]; | ||||
| if (!use_face_sel || mv->flag & SELECT) { | const char v_flag = mv->flag; | ||||
| if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) { | |||||
| accum->len += gmap->vert_to_loop[v_index].count; | accum->len += gmap->vert_to_loop[v_index].count; | ||||
| /* if a vertex is within the brush region, then add it's color to the blend. */ | /* if a vertex is within the brush region, then add it's color to the blend. */ | ||||
| for (int j = 0; j < gmap->vert_to_loop[v_index].count; j++) { | for (int j = 0; j < gmap->vert_to_loop[v_index].count; j++) { | ||||
| const int l_index = gmap->vert_to_loop[v_index].indices[j]; | const int l_index = gmap->vert_to_loop[v_index].indices[j]; | ||||
| col = (char *)(&lcol[l_index]); | col = (char *)(&lcol[l_index]); | ||||
| /* Color is squared to compensate the sqrt color encoding. */ | /* Color is squared to compensate the sqrt color encoding. */ | ||||
| accum->value[0] += col[0] * col[0]; | accum->value[0] += col[0] * col[0]; | ||||
| accum->value[1] += col[1] * col[1]; | accum->value[1] += col[1] * col[1]; | ||||
| Show All 36 Lines | static void do_vpaint_brush_draw_task_cb_ex( | ||||
| Brush *brush = data->brush; | Brush *brush = data->brush; | ||||
| StrokeCache *cache = ss->cache; | StrokeCache *cache = ss->cache; | ||||
| const float brush_strength = cache->bstrength; | const float brush_strength = cache->bstrength; | ||||
| uint *lcol = data->lcol; | uint *lcol = data->lcol; | ||||
| Scene *scene = CTX_data_scene(data->C); | Scene *scene = CTX_data_scene(data->C); | ||||
| float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; | float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; | ||||
| get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); | get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); | ||||
| const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; | const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; | ||||
| const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; | |||||
| const float radius = BKE_brush_size_get(scene, brush); | |||||
| SculptBrushTest test; | SculptBrushTest test; | ||||
| sculpt_brush_test_init(ss, &test); | sculpt_brush_test_init(ss, &test); | ||||
| /* For each vertex*/ | /* For each vertex */ | ||||
| PBVHVertexIter vd; | PBVHVertexIter vd; | ||||
| BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) | BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) | ||||
| { | { | ||||
| /* Test to see if the vertex coordinates are within the spherical brush region. */ | const bool do_occlude = (data->vp->flag & VP_NO_OCCLUDE) == 0; | ||||
| if (sculpt_brush_test(&test, vd.co)) { | float dist = 0.0f; | ||||
| const bool non_occlude = is_non_occluded(cache, vd, radius, do_occlude, &dist); | |||||
| /* Test to see if the vertex coordinates are within the spherical brush region or | |||||
| * occluded vertex for non-occluded mode. */ | |||||
| if (sculpt_brush_test(&test, vd.co) || non_occlude) { | |||||
| /* Note: Grids are 1:1 with corners (aka loops). | /* Note: Grids are 1:1 with corners (aka loops). | ||||
| * For grid based pbvh, take the vert whose loop cooresponds to the current grid. | * For grid based pbvh, take the vert whose loop cooresponds to the current grid. | ||||
| * Otherwise, take the current vert. */ | * Otherwise, take the current vert. */ | ||||
| const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; | const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; | ||||
| const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; | const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; | ||||
| const MVert *mv = &data->me->mvert[v_index]; | const MVert *mv = &data->me->mvert[v_index]; | ||||
| const char v_flag = mv->flag; | |||||
| /* If the vertex is selected for painting. */ | /* If the vertex is selected for painting. */ | ||||
| if (!use_face_sel || mv->flag & SELECT) { | if (!(use_face_sel || use_vert_sel) || v_flag & SELECT || (non_occlude && !use_vert_sel)) { | ||||
| /* Calc the dot prod. between ray norm on surf and current vert | /* Calc the dot prod. between ray norm on surf and current vert | ||||
| * (ie splash prevention factor), and only paint front facing verts. */ | * (ie splash prevention factor), and only paint front facing verts. */ | ||||
| const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; | float view_dot = (vd.no && !non_occlude) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; | ||||
| if (view_dot > 0.0f) { | if (view_dot > 0.0f) { | ||||
| const float brush_fade = BKE_brush_curve_strength(brush, test.dist, cache->radius); | const float brush_fade = BKE_brush_curve_strength(brush, dist, radius); | ||||
| uint color_final = data->vpd->paintcol; | uint color_final = data->vpd->paintcol; | ||||
| /* If we're painting with a texture, sample the texture color and alpha. */ | /* If we're painting with a texture, sample the texture color and alpha. */ | ||||
| float tex_alpha = 1.0; | float tex_alpha = 1.0; | ||||
| if (data->vpd->is_texbrush) { | if (data->vpd->is_texbrush) { | ||||
| handle_texture_brush( | handle_texture_brush( | ||||
| data, vd, brush_size_pressure, brush_alpha_pressure, | data, vd, brush_size_pressure, brush_alpha_pressure, | ||||
| &tex_alpha, &color_final); | &tex_alpha, &color_final); | ||||
| } | } | ||||
| /* For each poly owning this vert, paint each loop belonging to this vert. */ | /* For each poly owning this vert, paint each loop belonging to this vert. */ | ||||
| for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { | for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { | ||||
| const int p_index = gmap->vert_to_poly[v_index].indices[j]; | const int p_index = gmap->vert_to_poly[v_index].indices[j]; | ||||
| const int l_index = gmap->vert_to_loop[v_index].indices[j]; | const int l_index = gmap->vert_to_loop[v_index].indices[j]; | ||||
| BLI_assert(data->me->mloop[l_index].v == v_index); | BLI_assert(data->me->mloop[l_index].v == v_index); | ||||
| const MPoly *mp = &data->me->mpoly[p_index]; | const MPoly *mp = &data->me->mpoly[p_index]; | ||||
| if (!use_face_sel || mp->flag & ME_FACE_SEL) { | if (!use_face_sel || mp->flag & ME_FACE_SEL) { | ||||
| uint color_orig = 0; /* unused when array is NULL */ | uint color_orig = 0; /* unused when array is NULL */ | ||||
| if (ss->mode.vpaint.previous_color != NULL) { | if (ss->mode.vpaint.previous_color != NULL) { | ||||
| /* Get the previous loop color */ | /* Get the previous loop color */ | ||||
| if (ss->mode.vpaint.previous_color[l_index] == 0) { | if (ss->mode.vpaint.previous_color[l_index] == 0) { | ||||
| ss->mode.vpaint.previous_color[l_index] = lcol[l_index]; | ss->mode.vpaint.previous_color[l_index] = lcol[l_index]; | ||||
| } | } | ||||
| color_orig = ss->mode.vpaint.previous_color[l_index]; | color_orig = ss->mode.vpaint.previous_color[l_index]; | ||||
| } | } | ||||
| const float final_alpha = | float final_alpha = | ||||
| 255 * brush_fade * brush_strength * view_dot * | 255 * brush_fade * brush_strength * view_dot * | ||||
| tex_alpha * brush_alpha_pressure * grid_alpha; | tex_alpha * brush_alpha_pressure * grid_alpha; | ||||
| float mask_accum; | |||||
| mask_accum = ss->mode.vpaint.previous_accum[l_index]; | |||||
| if (brush->flag&BRUSH_ACCUMULATE) { | |||||
| final_alpha = final_alpha + mask_accum; | |||||
| } | |||||
| final_alpha = min_ff(final_alpha, 255.0f); | |||||
| ss->mode.vpaint.previous_accum[l_index] = final_alpha; | |||||
| /* Mix the new color with the original based on final_alpha. */ | /* Mix the new color with the original based on final_alpha. */ | ||||
| lcol[l_index] = vpaint_blend( | lcol[l_index] = vpaint_blend( | ||||
| data->vp, lcol[l_index], color_orig, color_final, | data->vp, lcol[l_index], color_orig, color_final, | ||||
| final_alpha, 255 * brush_strength); | final_alpha, 255 * brush_strength); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| Show All 13 Lines | static void do_vpaint_brush_blur_task_cb_ex( | ||||
| const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; | const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; | ||||
| Brush *brush = data->brush; | Brush *brush = data->brush; | ||||
| StrokeCache *cache = ss->cache; | StrokeCache *cache = ss->cache; | ||||
| const float brush_strength = cache->bstrength; | const float brush_strength = cache->bstrength; | ||||
| uint *lcol = data->lcol; | uint *lcol = data->lcol; | ||||
| float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; | float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; | ||||
| get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); | get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); | ||||
| const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; | const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; | ||||
| const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; | |||||
| const float radius = BKE_brush_size_get(scene, brush); | |||||
| SculptBrushTest test; | SculptBrushTest test; | ||||
| sculpt_brush_test_init(ss, &test); | sculpt_brush_test_init(ss, &test); | ||||
| /* For each vertex */ | /* For each vertex */ | ||||
| PBVHVertexIter vd; | PBVHVertexIter vd; | ||||
| BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) | BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) | ||||
| { | { | ||||
| /* Test to see if the vertex coordinates are within the spherical brush region. */ | float dist = 0.0f; | ||||
| if (sculpt_brush_test(&test, vd.co)) { | const bool do_occlude = (data->vp->flag & VP_NO_OCCLUDE) == 0; | ||||
| const bool non_occlude = is_non_occluded(cache, vd, radius, do_occlude, &dist); | |||||
| /* Test to see if the vertex coordinates are within the spherical brush region or | |||||
| * occluded vertex for non-occluded mode. */ | |||||
| if (sculpt_brush_test(&test, vd.co) || non_occlude) { | |||||
| /* For grid based pbvh, take the vert whose loop cooresponds to the current grid. | /* For grid based pbvh, take the vert whose loop cooresponds to the current grid. | ||||
| Otherwise, take the current vert. */ | * Otherwise, take the current vert. */ | ||||
| const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; | const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; | ||||
| const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; | const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; | ||||
| const MVert *mv = &data->me->mvert[v_index]; | const MVert *mv = &data->me->mvert[v_index]; | ||||
| const char v_flag = mv->flag; | |||||
| const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; | const float view_dot = (vd.no && !non_occlude) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; | ||||
| if (view_dot > 0.0f) { | if (view_dot > 0.0f) { | ||||
| const float brush_fade = BKE_brush_curve_strength(brush, test.dist, cache->radius); | const float brush_fade = BKE_brush_curve_strength(brush, dist, radius); | ||||
| /* If the vertex is selected for painting. */ | /* If the vertex is selected for painting. */ | ||||
| if (!use_face_sel || mv->flag & SELECT) { | if (!(use_face_sel || use_vert_sel) || v_flag & SELECT || (non_occlude && !use_vert_sel)) { | ||||
| /* Get the average poly color */ | /* Get the average poly color */ | ||||
| uint color_final = 0; | uint color_final = 0; | ||||
| int total_hit_loops = 0; | int total_hit_loops = 0; | ||||
| uint blend[4] = {0}; | uint blend[4] = {0}; | ||||
| for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { | for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { | ||||
| int p_index = gmap->vert_to_poly[v_index].indices[j]; | int p_index = gmap->vert_to_poly[v_index].indices[j]; | ||||
| const MPoly *mp = &data->me->mpoly[p_index]; | const MPoly *mp = &data->me->mpoly[p_index]; | ||||
| if (!use_face_sel || mp->flag & ME_FACE_SEL) { | if (!use_face_sel || mp->flag & ME_FACE_SEL) { | ||||
| ▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | static void do_vpaint_brush_smear_task_cb_ex( | ||||
| Brush *brush = data->brush; | Brush *brush = data->brush; | ||||
| StrokeCache *cache = ss->cache; | StrokeCache *cache = ss->cache; | ||||
| const float brush_strength = cache->bstrength; | const float brush_strength = cache->bstrength; | ||||
| uint *lcol = data->lcol; | uint *lcol = data->lcol; | ||||
| float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; | float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; | ||||
| get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); | get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); | ||||
| float brush_dir[3]; | float brush_dir[3]; | ||||
| const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; | const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; | ||||
| const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; | |||||
| const float radius = BKE_brush_size_get(scene, brush); | |||||
| sub_v3_v3v3(brush_dir, cache->location, cache->last_location); | sub_v3_v3v3(brush_dir, cache->location, cache->last_location); | ||||
| if (normalize_v3(brush_dir) != 0.0f) { | if (normalize_v3(brush_dir) != 0.0f) { | ||||
| SculptBrushTest test; | SculptBrushTest test; | ||||
| sculpt_brush_test_init(ss, &test); | sculpt_brush_test_init(ss, &test); | ||||
| /* For each vertex */ | /* For each vertex */ | ||||
| PBVHVertexIter vd; | PBVHVertexIter vd; | ||||
| BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) | BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) | ||||
| { | { | ||||
| /* Test to see if the vertex coordinates are within the spherical brush region. */ | float dist = 0.0f; | ||||
| if (sculpt_brush_test(&test, vd.co)) { | const bool do_occlude = (data->vp->flag & VP_NO_OCCLUDE) == 0; | ||||
| const bool non_occlude = is_non_occluded(cache, vd, radius, do_occlude, &dist); | |||||
| /* Test to see if the vertex coordinates are within the spherical brush region or | |||||
| * occluded vertex for non-occluded mode. */ | |||||
| if (sculpt_brush_test(&test, vd.co) || non_occlude) { | |||||
| /* For grid based pbvh, take the vert whose loop cooresponds to the current grid. | /* For grid based pbvh, take the vert whose loop cooresponds to the current grid. | ||||
| Otherwise, take the current vert. */ | * Otherwise, take the current vert. */ | ||||
| const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; | const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; | ||||
| const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; | const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; | ||||
| const MVert *mv_curr = &data->me->mvert[v_index]; | const MVert *mv_curr = &data->me->mvert[v_index]; | ||||
| const char v_flag = data->me->mvert[v_index].flag; | |||||
Not Done Inline ActionsThis happens to work because SELECT is 1. but isn't correct. - Other places too. campbellbarton: This happens to work because `SELECT` is 1. but isn't correct. - Other places too. | |||||
| /* if the vertex is selected for painting. */ | /* if the vertex is selected for painting. */ | ||||
| if (!use_face_sel || mv_curr->flag & SELECT) { | if (!(use_face_sel || use_vert_sel) || v_flag & SELECT || (non_occlude && !use_vert_sel)) { | ||||
| /* Calc the dot prod. between ray norm on surf and current vert | /* Calc the dot prod. between ray norm on surf and current vert | ||||
| (ie splash prevention factor), and only paint front facing verts. */ | (ie splash prevention factor), and only paint front facing verts. */ | ||||
| const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; | const float view_dot = (vd.no && !non_occlude) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; | ||||
| if (view_dot > 0.0f) { | if (view_dot > 0.0f) { | ||||
| const float brush_fade = BKE_brush_curve_strength(brush, test.dist, cache->radius); | const float brush_fade = BKE_brush_curve_strength(brush, dist, radius); | ||||
| bool do_color = false; | bool do_color = false; | ||||
| /* Minimum dot product between brush direction and current | /* Minimum dot product between brush direction and current | ||||
| * to neighbor direction is 0.0, meaning orthogonal. */ | * to neighbor direction is 0.0, meaning orthogonal. */ | ||||
| float stroke_dot_max = 0.0f; | float stroke_dot_max = 0.0f; | ||||
| /* Get the color of the loop in the opposite direction of the brush movement */ | /* Get the color of the loop in the opposite direction of the brush movement */ | ||||
| uint color_final = 0; | uint color_final = 0; | ||||
| ▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | |||||
| static void vpaint_paint_leaves( | static void vpaint_paint_leaves( | ||||
| bContext *C, Sculpt *sd, VPaint *vp, struct VPaintData *vpd, | bContext *C, Sculpt *sd, VPaint *vp, struct VPaintData *vpd, | ||||
| Object *ob, Mesh *me, PBVHNode **nodes, int totnode) | Object *ob, Mesh *me, PBVHNode **nodes, int totnode) | ||||
| { | { | ||||
| Brush *brush = ob->sculpt->cache->brush; | Brush *brush = ob->sculpt->cache->brush; | ||||
| SculptThreadedTaskData data = { | SculptThreadedTaskData data = { | ||||
| .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .vpd = vpd, | .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .vpd = vpd, | ||||
| .lcol = (uint *)me->mloopcol, .me = me, .C = C, | .lcol = (uint *)me->mloopcol, .me = me, .C = C, | ||||
| }; | }; | ||||
| switch (brush->vertexpaint_tool) { | switch (brush->vertexpaint_tool) { | ||||
| case PAINT_BLEND_AVERAGE: | case PAINT_BLEND_AVERAGE: | ||||
| calculate_average_color(&data, nodes, totnode); | calculate_average_color(&data, nodes, totnode); | ||||
| BLI_task_parallel_range_ex( | BLI_task_parallel_range_ex( | ||||
| 0, totnode, &data, NULL, 0, | 0, totnode, &data, NULL, 0, | ||||
| do_vpaint_brush_draw_task_cb_ex, true, false); | do_vpaint_brush_draw_task_cb_ex, true, false); | ||||
| break; | break; | ||||
| ▲ Show 20 Lines • Show All 159 Lines • ▼ Show 20 Lines | |||||
| static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) | static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| int retval; | int retval; | ||||
| op->customdata = paint_stroke_new(C, op, sculpt_stroke_get_location, vpaint_stroke_test_start, | op->customdata = paint_stroke_new(C, op, sculpt_stroke_get_location, vpaint_stroke_test_start, | ||||
| vpaint_stroke_update_step, NULL, | vpaint_stroke_update_step, NULL, | ||||
| vpaint_stroke_done, event->type); | vpaint_stroke_done, event->type); | ||||
| if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) { | if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) { | ||||
| paint_stroke_data_free(op); | paint_stroke_data_free(op); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| /* add modal handler */ | /* add modal handler */ | ||||
| WM_event_add_modal_handler(C, op); | WM_event_add_modal_handler(C, op); | ||||
| OPERATOR_RETVAL_CHECK(retval); | OPERATOR_RETVAL_CHECK(retval); | ||||
| BLI_assert(retval == OPERATOR_RUNNING_MODAL); | BLI_assert(retval == OPERATOR_RUNNING_MODAL); | ||||
| return OPERATOR_RUNNING_MODAL; | return OPERATOR_RUNNING_MODAL; | ||||
| } | } | ||||
| static int vpaint_exec(bContext *C, wmOperator *op) | static int vpaint_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| op->customdata = paint_stroke_new(C, op, sculpt_stroke_get_location, vpaint_stroke_test_start, | op->customdata = paint_stroke_new(C, op, sculpt_stroke_get_location, vpaint_stroke_test_start, | ||||
| vpaint_stroke_update_step, NULL, | vpaint_stroke_update_step, NULL, | ||||
| vpaint_stroke_done, 0); | vpaint_stroke_done, 0); | ||||
| Show All 16 Lines | |||||
| } | } | ||||
| void PAINT_OT_vertex_paint(wmOperatorType *ot) | void PAINT_OT_vertex_paint(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Vertex Paint"; | ot->name = "Vertex Paint"; | ||||
| ot->idname = "PAINT_OT_vertex_paint"; | ot->idname = "PAINT_OT_vertex_paint"; | ||||
| ot->description = "Paint a stroke in the active vertex color layer"; | ot->description = "Paint a stroke in the active vertex color layer"; | ||||
| /* api callbacks */ | /* api callbacks */ | ||||
| ot->invoke = vpaint_invoke; | ot->invoke = vpaint_invoke; | ||||
| ot->modal = paint_stroke_modal; | ot->modal = paint_stroke_modal; | ||||
| ot->exec = vpaint_exec; | ot->exec = vpaint_exec; | ||||
| ot->poll = vertex_paint_poll; | ot->poll = vertex_paint_poll; | ||||
| ot->cancel = vpaint_cancel; | ot->cancel = vpaint_cancel; | ||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; | ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; | ||||
| paint_stroke_operator_properties(ot); | paint_stroke_operator_properties(ot); | ||||
| } | } | ||||
| /* ********************** weight from bones operator ******************* */ | /* ********************** weight from bones operator ******************* */ | ||||
| Show All 18 Lines | static int weight_from_bones_exec(bContext *C, wmOperator *op) | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); | WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void PAINT_OT_weight_from_bones(wmOperatorType *ot) | void PAINT_OT_weight_from_bones(wmOperatorType *ot) | ||||
| { | { | ||||
| static EnumPropertyItem type_items[] = { | static EnumPropertyItem type_items[] = { | ||||
| {ARM_GROUPS_AUTO, "AUTOMATIC", 0, "Automatic", "Automatic weights from bones"}, | {ARM_GROUPS_AUTO, "AUTOMATIC", 0, "Automatic", "Automatic weights from bones"}, | ||||
| {ARM_GROUPS_ENVELOPE, "ENVELOPES", 0, "From Envelopes", "Weights from envelopes with user defined radius"}, | {ARM_GROUPS_ENVELOPE, "ENVELOPES", 0, "From Envelopes", "Weights from envelopes with user defined radius"}, | ||||
| {0, NULL, 0, NULL, NULL}}; | {0, NULL, 0, NULL, NULL}}; | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Weight from Bones"; | ot->name = "Weight from Bones"; | ||||
| ot->idname = "PAINT_OT_weight_from_bones"; | ot->idname = "PAINT_OT_weight_from_bones"; | ||||
| ot->description = "Set the weights of the groups matching the attached armature's selected bones, " | ot->description = "Set the weights of the groups matching the attached armature's selected bones, " | ||||
| "using the distance between the vertices and the bones"; | "using the distance between the vertices and the bones"; | ||||
| /* api callbacks */ | /* api callbacks */ | ||||
| ot->exec = weight_from_bones_exec; | ot->exec = weight_from_bones_exec; | ||||
| ot->invoke = WM_menu_invoke; | ot->invoke = WM_menu_invoke; | ||||
| ot->poll = weight_from_bones_poll; | ot->poll = weight_from_bones_poll; | ||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* properties */ | /* properties */ | ||||
| ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights"); | ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights"); | ||||
| } | } | ||||
| /* *** VGroups Gradient *** */ | /* *** VGroups Gradient *** */ | ||||
| ▲ Show 20 Lines • Show All 291 Lines • ▼ Show 20 Lines | static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| } | } | ||||
| return ret; | return ret; | ||||
| } | } | ||||
| void PAINT_OT_weight_gradient(wmOperatorType *ot) | void PAINT_OT_weight_gradient(wmOperatorType *ot) | ||||
| { | { | ||||
| /* defined in DNA_space_types.h */ | /* defined in DNA_space_types.h */ | ||||
| static EnumPropertyItem gradient_types[] = { | static EnumPropertyItem gradient_types[] = { | ||||
| {WPAINT_GRADIENT_TYPE_LINEAR, "LINEAR", 0, "Linear", ""}, | {WPAINT_GRADIENT_TYPE_LINEAR, "LINEAR", 0, "Linear", ""}, | ||||
| {WPAINT_GRADIENT_TYPE_RADIAL, "RADIAL", 0, "Radial", ""}, | {WPAINT_GRADIENT_TYPE_RADIAL, "RADIAL", 0, "Radial", ""}, | ||||
| {0, NULL, 0, NULL, NULL} | {0, NULL, 0, NULL, NULL} | ||||
| }; | }; | ||||
| PropertyRNA *prop; | PropertyRNA *prop; | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Weight Gradient"; | ot->name = "Weight Gradient"; | ||||
| ot->idname = "PAINT_OT_weight_gradient"; | ot->idname = "PAINT_OT_weight_gradient"; | ||||
| ot->description = "Draw a line to apply a weight gradient to selected vertices"; | ot->description = "Draw a line to apply a weight gradient to selected vertices"; | ||||
| /* api callbacks */ | /* api callbacks */ | ||||
| ot->invoke = paint_weight_gradient_invoke; | ot->invoke = paint_weight_gradient_invoke; | ||||
| ot->modal = paint_weight_gradient_modal; | ot->modal = paint_weight_gradient_modal; | ||||
| ot->exec = paint_weight_gradient_exec; | ot->exec = paint_weight_gradient_exec; | ||||
| ot->poll = weight_paint_poll; | ot->poll = weight_paint_poll; | ||||
| ot->cancel = WM_gesture_straightline_cancel; | ot->cancel = WM_gesture_straightline_cancel; | ||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", ""); | prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", ""); | ||||
| RNA_def_property_flag(prop, PROP_SKIP_SAVE); | RNA_def_property_flag(prop, PROP_SKIP_SAVE); | ||||
| WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT); | WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT); | ||||
| } | } | ||||
| static bool weight_to_vert_convert(bContext *C) | |||||
| { | |||||
| Object *ob = CTX_data_active_object(C); | |||||
| Mesh *me; | |||||
| const MPoly *mp; | |||||
| int vgroup_active; | |||||
| if (((me = BKE_mesh_from_object(ob)) == NULL || (me->dvert == NULL) || | |||||
| (me->mloopcol == NULL && (make_vertexcol(ob)) == false))) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| mp = me->mpoly; | |||||
| vgroup_active = ob->actdef - 1; | |||||
| for (int i = 0; i < me->totpoly; i++, mp++) { | |||||
| MLoopCol *lcol = &me->mloopcol[mp->loopstart]; | |||||
| uint j = 0; | |||||
| do{ | |||||
| uint vidx = me->mloop[mp->loopstart + j].v; | |||||
| const float weight = defvert_find_weight(&me->dvert[vidx], vgroup_active); | |||||
| const char grayscale = weight * 255; | |||||
| lcol->r = grayscale; | |||||
| lcol->b = grayscale; | |||||
| lcol->g = grayscale; | |||||
| lcol++; | |||||
| j++; | |||||
| } while (j <= mp->totloop - 1); | |||||
| } | |||||
| DAG_id_tag_update(&ob->id, OB_RECALC_DATA); | |||||
| WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); | |||||
| return true; | |||||
| } | |||||
| static int weight_to_vert_convert_exec(bContext *C, wmOperator *UNUSED(op)) | |||||
| { | |||||
| if (weight_to_vert_convert(C)) { | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| void PAINT_OT_weight_to_vertex_convert(wmOperatorType *ot) | |||||
| { | |||||
| /* identifiers */ | |||||
| ot->name = "Weight to Vertex Convert"; | |||||
| ot->idname = "PAINT_OT_weight_to_vertex_convert"; | |||||
| ot->description = "Converts the weight color into the black and white vertex color"; | |||||
| /* api callback */ | |||||
| ot->exec = weight_to_vert_convert_exec; | |||||
| ot->poll = vertex_weight_paint_mode_poll; | |||||
| /* flags */ | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| } | |||||
luminocity -> typo? or intended?