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, | |||||
| const bool use_alpha, const uchar alpha_value, ColorLock *lock) | |||||
| { | { | ||||
| 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) { | ||||
| cp = (uchar *)&col2; | |||||
| cp1 = (uchar *)&col1; | |||||
| cp[3] = use_alpha ? alpha_value : cp[3] ; | |||||
| cp[0] = lock->lock_red ? cp1[0] : cp[0]; | |||||
| cp[1] = lock->lock_green ? cp1[1] : cp[1]; | |||||
| cp[2] = lock->lock_blue ? cp1[2] : cp[2]; | |||||
| cp[3] = lock->lock_alpha ? cp1[3] : cp[3]; | |||||
| 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] = lock->lock_red? cp1[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] = lock->lock_green ? cp1[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] = lock->lock_blue ? cp1[2] : round_fl_to_uchar(sqrtf(divide_round_i((mfac * b1 + fac * b2), 255))); | ||||
| cp[3] = 255; | cp[3] = lock->lock_alpha ? cp1[3] : (use_alpha ? round_fl_to_uchar(sqrtf(divide_round_i((mfac * a1 + fac * a2), 255))) : 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, | |||||
| const bool use_alpha, ColorLock *lock) | |||||
| { | { | ||||
| 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] = lock->lock_red ? cp1[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] = lock->lock_green ? cp1[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] = lock->lock_blue ? cp1[2] : ((temp > 254) ? 255 : temp); | ||||
| cp[3] = 255; | temp = cp1[3] + divide_round_i((fac * cp2[3]), 255); | ||||
| cp[3] = lock->lock_alpha ? cp1[3] : (use_alpha ? ((temp > 254) ? 255 : temp) : 255); | |||||
| 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, | |||||
| const bool use_alpha, ColorLock *lock) | |||||
| { | { | ||||
| 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] = lock->lock_red ? cp1[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] = lock->lock_green ? cp1[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] = lock->lock_blue ? cp1[2] : ((temp < 0) ? 0 : temp); | ||||
| cp[3] = 255; | temp = cp1[3] - divide_round_i((fac * cp2[3]), 255); | ||||
| cp[3] = lock->lock_alpha ? cp1[3] : (use_alpha ? ((temp < 0) ? 0 : temp) : 255); | |||||
| 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, | |||||
| const bool use_alpha, ColorLock *lock) | |||||
| { | { | ||||
| 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] = lock->lock_red ? cp1[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] = lock->lock_green ? cp1[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] = lock->lock_blue ? cp1[2] : (divide_round_i(mfac * cp1[2] * 255 + fac * cp2[2] * cp1[2], 255 * 255)); | ||||
| cp[3] = 255; | cp[3] = lock->lock_alpha ? cp1[3] : (use_alpha ? (divide_round_i(mfac * cp1[3] * 255 + fac * cp2[3] * cp1[3], 255 * 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, | ||||
| const bool use_alpha, const uchar alpha_value, ColorLock *lock) | |||||
| { | { | ||||
| 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; | ||||
| } | } | ||||
| else if (fac >= 255) { | else if (fac >= 255) { | ||||
| cp = (uchar *)&col2; | |||||
| cp[3] = use_alpha ? alpha_value : cp[3]; | |||||
| 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; | ||||
| /* See if are lighter, if so mix, else don't do anything. | /* See if are lighter, if so mix, else don't do anything. | ||||
| * 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] = lock->lock_red ? cp1[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] = lock->lock_green ? cp1[2] : (divide_round_i(mfac * cp1[1] + fac * cp2[1], 255)); | ||||
| cp[2] = divide_round_i(mfac * cp1[2] + fac * cp2[2], 255); | cp[2] = lock->lock_blue ? cp1[3] : (divide_round_i(mfac * cp1[2] + fac * cp2[2], 255)); | ||||
| cp[3] = 255; | cp[3] = lock->lock_alpha ? cp1[4] : (use_alpha ? (divide_round_i(mfac * cp1[3] + fac * cp2[3], 255)) : 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, | |||||
| const bool use_alpha, const uchar alpha_value, ColorLock *lock) | |||||
| { | { | ||||
| 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; | ||||
| } | } | ||||
| else if (fac >= 255) { | else if (fac >= 255) { | ||||
| cp = (uchar *)&col2; | |||||
| cp1 = (uchar *)&col1; | |||||
| cp[3] = use_alpha ? alpha_value : cp[3]; | |||||
| cp[0] = lock->lock_red ? cp1[0] : cp[0]; | |||||
| cp[1] = lock->lock_green ? cp1[1] : cp[1]; | |||||
| cp[2] = lock->lock_blue ? cp1[2] : cp[2]; | |||||
| cp[3] = lock->lock_alpha ? cp1[3] : cp[3]; | |||||
| 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; | ||||
| /* See if were darker, if so mix, else don't do anything. | /* See if were darker, if so mix, else don't do anything. | ||||
| * 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] = lock->lock_red ? cp1[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] = lock->lock_green ? cp1[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] = lock->lock_blue ? cp1[2] : (divide_round_i((mfac * cp1[2] + fac * cp2[2]), 255)); | ||||
| cp[3] = 255; | cp[3] = lock->lock_alpha ? cp1[3] : (use_alpha ? (divide_round_i((mfac * cp1[3] + fac * cp2[3]), 255)) : 255); | ||||
| return col; | |||||
| } | |||||
| BLI_INLINE uint mcol_colordodge( | |||||
| uint col1, uint col2, int fac, | |||||
| const bool use_alpha, ColorLock *lock) | |||||
| { | |||||
| 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] = lock->lock_red ? cp1[0] : ((mfac * cp1[0] + temp * fac) / 255); | |||||
| temp = (cp2[1] == 255) ? 255 : min_ii((cp1[1] * 225) / (255 - cp2[1]), 255); | |||||
| cp[1] = lock->lock_green ? cp1[1] : ((mfac * cp1[1] + temp * fac) / 255); | |||||
| temp = (cp2[2] == 255) ? 255 : min_ii((cp1[2] * 225 )/ (255 - cp2[2]), 255); | |||||
| cp[2] = lock->lock_blue ? cp1[2] : ((mfac * cp1[2] + temp * fac) / 255); | |||||
| temp = (cp2[3] == 255) ? 255 : min_ii((cp1[3] * 225) / (255 - cp2[3]), 255); | |||||
| cp[3] = lock->lock_alpha ? cp1[3] : (use_alpha ? ((mfac * cp1[3] + temp * fac) / 255) : 255); | |||||
| return col; | |||||
| } | |||||
| BLI_INLINE uint mcol_difference( | |||||
| uint col1, uint col2, int fac, | |||||
| const bool use_alpha, ColorLock *lock) | |||||
| { | |||||
| 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] = lock->lock_red ? cp1[0] : ((mfac * cp1[0] + temp * fac) / 255); | |||||
| temp = abs(cp1[1] - cp2[1]); | |||||
| cp[1] = lock->lock_green ? cp1[1] : ((mfac * cp1[1] + temp * fac) / 255); | |||||
| temp = abs(cp1[2] - cp2[2]); | |||||
| cp[2] = lock->lock_blue ? cp1[2] : ((mfac * cp1[2] + temp * fac) / 255); | |||||
| temp = abs(cp1[3] - cp2[3]); | |||||
| cp[3] = lock->lock_alpha ? cp1[3] : (use_alpha ? ((mfac * cp1[3] + temp * fac) / 255) : 255); | |||||
| return col; | |||||
| } | |||||
| BLI_INLINE uint mcol_screen( | |||||
| uint col1, uint col2, int fac, | |||||
| const bool use_alpha, ColorLock *lock) | |||||
| { | |||||
| 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] = lock->lock_red ? cp1[0] : ((mfac * cp1[0] + temp * fac) / 255); | |||||
| temp = max_ii(255 - (((255 - cp1[1]) * (255 - cp2[1])) / 255), 0); | |||||
| cp[1] = lock->lock_green ? cp1[1] : ((mfac * cp1[1] + temp * fac) / 255); | |||||
| temp = max_ii(255 - (((255 - cp1[2]) * (255 - cp2[2])) / 255), 0); | |||||
| cp[2] = lock->lock_blue ? cp1[2] : ((mfac * cp1[2] + temp * fac) / 255); | |||||
| temp = max_ii(255 - (((255 - cp1[3]) * (255 - cp2[3])) / 255), 0); | |||||
| cp[3] = lock->lock_alpha ? cp1[3] : (use_alpha ? ((mfac * cp1[3] + temp * fac) / 255) : 255); | |||||
| return col; | |||||
| } | |||||
| BLI_INLINE uint mcol_hardlight( | |||||
| uint col1, uint col2, int fac, | |||||
| const bool use_alpha, ColorLock *lock) | |||||
| { | |||||
| 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 ((&lock->lock_red)[i]) | |||||
| continue; | |||||
| if (!use_alpha && i == 3) { | |||||
| cp[i] = 255; | |||||
| continue; | |||||
| } | |||||
| 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, | |||||
| const bool use_alpha, ColorLock *lock) | |||||
| { | |||||
| 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 ((&lock->lock_red)[i]) | |||||
| continue; | |||||
| if (!use_alpha && i == 3) { | |||||
| cp[i] = 255; | |||||
| continue; | |||||
| } | |||||
| 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, | |||||
| const bool use_alpha, ColorLock *lock) | |||||
| { | |||||
| 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 ((&lock->lock_red)[i]) | |||||
| continue; | |||||
| if (!use_alpha && i == 3) { | |||||
| cp[i] = 255; | |||||
| continue; | |||||
| } | |||||
| 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, | |||||
| const bool use_alpha, ColorLock *lock) | |||||
| { | |||||
| 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 ((&lock->lock_red)[i]) | |||||
| continue; | |||||
| if (!use_alpha && i == 3) { | |||||
| cp[i] = 255; | |||||
| continue; | |||||
| } | |||||
| temp = 127 - ((2 * (cp1[i] - 127) * (cp2[i] - 127)) / 255); | |||||
| cp[i] = (temp * fac + cp1[i] * mfac) / 255; | |||||
| } | |||||
| return col; | return col; | ||||
| } | } | ||||
| BLI_INLINE uint mcol_luminosity( | |||||
mont29: luminocity -> typo? or intended? | |||||
| uint col1, uint col2, int fac, | |||||
| const bool use_alpha, ColorLock *lock) | |||||
| { | |||||
| 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] = lock->lock_red ? cp1[0] : (((int)(r * 255.0f) * fac + mfac * cp1[0]) / 255); | |||||
| cp[1] = lock->lock_green ? cp1[1] : (((int)(g * 255.0f) * fac + mfac * cp1[1]) / 255); | |||||
| cp[2] = lock->lock_blue ? cp1[2] : (((int)(b * 255.0f) * fac + mfac * cp1[2]) / 255); | |||||
| cp[3] = lock->lock_alpha ? cp1[3] : (use_alpha ? (((int)(cp2[3]) * fac + mfac * cp1[3]) / 255) : 255); | |||||
| return col; | |||||
| } | |||||
| BLI_INLINE uint mcol_saturation( | |||||
| uint col1, uint col2, int fac, | |||||
| const bool use_alpha, ColorLock *lock) | |||||
| { | |||||
| 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); | |||||
| if (s1 > EPS_SATURATION) { | |||||
| s1 = s2; | |||||
| } | |||||
| hsv_to_rgb(h1, s1, v1, &r, &g, &b); | |||||
| cp[0] = lock->lock_red ? cp1[0] : (((int)(r * 255.0f) * fac + mfac * cp1[0]) / 255); | |||||
| cp[1] = lock->lock_green ? cp1[1] : (((int)(g * 255.0f) * fac + mfac * cp1[1]) / 255); | |||||
| cp[2] = lock->lock_blue ? cp1[2] : (((int)(b * 255.0f) * fac + mfac * cp1[2]) / 255); | |||||
| cp[3] = lock->lock_alpha ? cp1[3] : (use_alpha ? (((int)(cp2[3]) * fac + mfac * cp1[3]) / 255) : 255); | |||||
| return col; | |||||
| } | |||||
| BLI_INLINE uint mcol_hue( | |||||
| uint col1, uint col2, int fac, | |||||
| const bool use_alpha, ColorLock *lock) | |||||
| { | |||||
| 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] = lock->lock_red ? cp1[0] : (((int)(r * 255.0f) * fac + mfac * cp1[0]) / 255); | |||||
| cp[1] = lock->lock_green ? cp1[1] : (((int)(g * 255.0f) * fac + mfac * cp1[1]) / 255); | |||||
| cp[2] = lock->lock_blue ? cp1[2] : (((int)(b * 255.0f) * fac + mfac * cp1[2]) / 255); | |||||
| cp[3] = lock->lock_alpha ? cp1[3] : (use_alpha ? (((int)(cp2[3]) * fac + mfac * cp1[3]) / 255) : 255); | |||||
| 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 uint paintcol, const int alpha_i) | const int tool, const uint col, | ||||
| const uint paintcol, const int alpha_i, | |||||
| const bool use_alpha, const uchar alpha_value, ColorLock *lock) | |||||
| { | { | ||||
| 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, use_alpha, alpha_value, lock); | ||||
| case PAINT_BLEND_AVERAGE: return mcol_blend(col, paintcol, alpha_i); | case PAINT_BLEND_AVERAGE: return mcol_blend(col, paintcol, alpha_i, use_alpha, alpha_value, lock); | ||||
| case PAINT_BLEND_SMEAR: return mcol_blend(col, paintcol, alpha_i); | case PAINT_BLEND_SMEAR: return mcol_blend(col, paintcol, alpha_i, use_alpha, alpha_value, lock); | ||||
| case PAINT_BLEND_ADD: return mcol_add(col, paintcol, alpha_i); | case PAINT_BLEND_ADD: return mcol_add(col, paintcol, alpha_i, use_alpha, lock); | ||||
| case PAINT_BLEND_SUB: return mcol_sub(col, paintcol, alpha_i); | case PAINT_BLEND_SUB: return mcol_sub(col, paintcol, alpha_i, use_alpha, lock); | ||||
| case PAINT_BLEND_MUL: return mcol_mul(col, paintcol, alpha_i); | case PAINT_BLEND_MUL: return mcol_mul(col, paintcol, alpha_i, use_alpha, lock); | ||||
| case PAINT_BLEND_LIGHTEN: return mcol_lighten(col, paintcol, alpha_i); | case PAINT_BLEND_LIGHTEN: return mcol_lighten(col, paintcol, alpha_i, use_alpha, alpha_value, lock); | ||||
| case PAINT_BLEND_DARKEN: return mcol_darken(col, paintcol, alpha_i); | case PAINT_BLEND_DARKEN: return mcol_darken(col, paintcol, alpha_i, use_alpha, alpha_value, lock); | ||||
| case PAINT_BLEND_COLORDODGE: return mcol_colordodge(col, paintcol, alpha_i, use_alpha, lock); | |||||
| case PAINT_BLEND_DIFFERENCE: return mcol_difference(col, paintcol, alpha_i, use_alpha, lock); | |||||
| case PAINT_BLEND_SCREEN: return mcol_screen(col, paintcol, alpha_i, use_alpha, lock); | |||||
| case PAINT_BLEND_HARDLIGHT: return mcol_hardlight(col, paintcol, alpha_i, use_alpha, lock); | |||||
| case PAINT_BLEND_OVERLAY: return mcol_overlay(col, paintcol, alpha_i, use_alpha, lock); | |||||
| case PAINT_BLEND_SOFTLIGHT: return mcol_softlight(col, paintcol, alpha_i, use_alpha, lock); | |||||
| case PAINT_BLEND_EXCLUSION: return mcol_exclusion(col, paintcol, alpha_i, use_alpha, lock); | |||||
| case PAINT_BLEND_LUMINOCITY: return mcol_luminosity(col, paintcol, alpha_i, use_alpha, lock); | |||||
| case PAINT_BLEND_SATURATION: return mcol_saturation(col, paintcol, alpha_i, use_alpha, lock); | |||||
| case PAINT_BLEND_HUE: return mcol_hue(col, paintcol, alpha_i, use_alpha, lock); | |||||
| default: | default: | ||||
| BLI_assert(0); | BLI_assert(0); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| } | } | ||||
| static void initialise_color_lock(VPaint *vp, ColorLock *lock) | |||||
| { | |||||
| lock->lock_red = vp->flag & VP_LOCK_R; | |||||
| lock->lock_green = vp->flag & VP_LOCK_G; | |||||
| lock->lock_blue = vp->flag & VP_LOCK_B; | |||||
| lock->lock_alpha = vp->flag & VP_LOCK_A; | |||||
| } | |||||
| /* 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 col, uint colorig, | ||||
| const uint paintcol, const int alpha_i, | uint paintcol, 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, const bool use_alpha, const uchar alpha_value) | ||||
| { | { | ||||
| 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; | ||||
| ColorLock lock; | |||||
| col = vpaint_blend_tool(tool, col, paintcol, alpha_i); | initialise_color_lock(vp, &lock); | ||||
| { | |||||
| uchar *cp = (uchar *)&paintcol; | |||||
| cp[3] = use_alpha ? alpha_value : 255; | |||||
| } | |||||
| col = vpaint_blend_tool(tool, col, paintcol, alpha_i, use_alpha, alpha_value, &lock); | |||||
| /* 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 testcol, a; | ||||
| char *cp, *ct, *co; | char *cp, *ct, *co; | ||||
| testcol = vpaint_blend_tool(tool, colorig, paintcol, brush_alpha_value_i); | testcol = vpaint_blend_tool(tool, colorig, paintcol, brush_alpha_value_i, use_alpha, alpha_value, &lock); | ||||
| cp = (char *)&col; | cp = (char *)&col; | ||||
| ct = (char *)&testcol; | ct = (char *)&testcol; | ||||
| co = (char *)&colorig; | co = (char *)&colorig; | ||||
| 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]; | ||||
| ▲ Show 20 Lines • Show All 961 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 20 Lines • Show All 617 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 *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); | |||||
| *dist = sqrtf(dist_sq); | |||||
| if (dist_sq <= radius*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; | ||||
| bool non_occlude; | |||||
| float dist; | |||||
| 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_OCCLUDE) != 0; | |||||
| dist = 0; | |||||
| 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]; | ||||
| float dist; | |||||
| bool non_occlude; | |||||
| 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) | ||||
| { | { | ||||
| const bool do_occlude = (data->vp->flag & VP_OCCLUDE) != 0; | |||||
| dist = 0; | |||||
| 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; | ||||
| float dist; | |||||
| bool non_occlude; | |||||
| 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_OCCLUDE) != 0; | |||||
| dist = 0; | |||||
| 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 473 Lines • ▼ Show 20 Lines | static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) | ||||
| /* 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); | ||||
| ▲ Show 20 Lines • Show All 177 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 bool use_alpha = brush->flag & BRUSH_ALPHA_VPAINT; | |||||
| const uchar alpha_paint = brush->alpha_paint; | |||||
| bool non_occlude; | |||||
| float dist; | |||||
| 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_OCCLUDE) != 0; | ||||
| if (sculpt_brush_test(&test, vd.co)) { | dist = 0; | ||||
| 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, use_alpha, alpha_paint); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| BKE_pbvh_vertex_iter_end; | BKE_pbvh_vertex_iter_end; | ||||
| } | } | ||||
| Show All 9 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 bool use_alpha = brush->flag & BRUSH_ALPHA_VPAINT; | |||||
| const uchar alpha_paint = brush->alpha_paint; | |||||
| bool non_occlude; | |||||
| float dist; | |||||
| 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_OCCLUDE) != 0; | ||||
| if (sculpt_brush_test(&test, vd.co)) { | dist = 0; | ||||
| 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 All 34 Lines | if (sculpt_brush_test(&test, vd.co) || non_occlude) { | ||||
| } | } | ||||
| const float final_alpha = | const float final_alpha = | ||||
| 255 * brush_fade * brush_strength * view_dot * | 255 * brush_fade * brush_strength * view_dot * | ||||
| brush_alpha_pressure * grid_alpha; | brush_alpha_pressure * grid_alpha; | ||||
| /* Mix the new color with the original | /* Mix the new color with the original | ||||
| * based on the brush strength and the curve. */ | * based on the brush strength and the curve. */ | ||||
| lcol[l_index] = vpaint_blend( | lcol[l_index] = vpaint_blend( | ||||
| data->vp, lcol[l_index], color_orig, *((uint *)col), | data->vp, lcol[l_index], color_orig, *((uint *)col), | ||||
| final_alpha, 255 * brush_strength); | final_alpha, 255 * brush_strength, use_alpha, alpha_paint); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| BKE_pbvh_vertex_iter_end; | BKE_pbvh_vertex_iter_end; | ||||
| Show All 11 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 bool use_alpha = brush->flag & BRUSH_ALPHA_VPAINT; | |||||
| const uchar alpha_paint = brush->alpha_paint; | |||||
| float dist; | |||||
| bool non_occlude; | |||||
| 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. */ | const bool do_occlude = (data->vp->flag & VP_OCCLUDE) != 0; | ||||
| if (sculpt_brush_test(&test, vd.co)) { | dist = 0; | ||||
| 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 43 Lines • ▼ Show 20 Lines | BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) | ||||
| } | } | ||||
| const float final_alpha = | const float final_alpha = | ||||
| 255 * brush_fade * brush_strength * | 255 * brush_fade * brush_strength * | ||||
| view_dot * brush_alpha_pressure * grid_alpha; | view_dot * brush_alpha_pressure * grid_alpha; | ||||
| /* Mix the new color with the original | /* Mix the new color with the original | ||||
| * based on the brush strength and the curve. */ | * based on the brush strength and the curve. */ | ||||
| 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, use_alpha, alpha_paint); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| BKE_pbvh_vertex_iter_end; | BKE_pbvh_vertex_iter_end; | ||||
| ▲ Show 20 Lines • Show All 643 Lines • ▼ Show 20 Lines | void PAINT_OT_weight_gradient(wmOperatorType *ot) | ||||
| /* 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?