diff options
-rw-r--r-- | release/scripts/startup/bl_ui/space_view3d_toolbar.py | 42 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_paint.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/paint.c | 6 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_cursor.c | 391 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_image_proj.c | 6 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_brush.c | 2 |
6 files changed, 351 insertions, 98 deletions
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 847d1fa43e4..c0c84c4449f 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -670,6 +670,19 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel): col.prop(brush, "use_persistent") col.operator("sculpt.set_persistent_base") + col = layout.column(align=True) + col.label(text="Overlay:") + + row = col.row() + if brush.use_cursor_overlay: + row.prop(brush, "use_cursor_overlay", toggle=True, text="", icon='RESTRICT_VIEW_OFF') + else: + row.prop(brush, "use_cursor_overlay", toggle=True, text="", icon='RESTRICT_VIEW_ON') + + sub = row.row() + sub.prop(brush, "cursor_overlay_alpha", text="Alpha") + sub.prop(brush, "cursor_overlay_override", toggle=True, text="", icon='BRUSH_DATA') + # Texture Paint Mode # elif context.image_paint_object and brush: @@ -693,6 +706,20 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel): col.active = (brush.blend not in {'ERASE_ALPHA', 'ADD_ALPHA'}) col.prop(brush, "use_alpha") + col = layout.column(align=True) + col.label(text="Overlay:") + + row = col.row() + if brush.use_cursor_overlay: + row.prop(brush, "use_cursor_overlay", toggle=True, text="", icon='RESTRICT_VIEW_OFF') + else: + row.prop(brush, "use_cursor_overlay", toggle=True, text="", icon='RESTRICT_VIEW_ON') + + sub = row.row() + sub.prop(brush, "cursor_overlay_alpha", text="Alpha") + sub.prop(brush, "cursor_overlay_override", toggle=True, text="", icon='BRUSH_DATA') + + # Weight Paint Mode # elif context.weight_paint_object and brush: layout.prop(toolsettings, "use_auto_normalize", text="Auto Normalize") @@ -736,6 +763,19 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel): col.prop(brush, "vertex_tool", text="Blend") + col = layout.column(align=True) + col.label(text="Overlay:") + + row = col.row() + if brush.use_cursor_overlay: + row.prop(brush, "use_cursor_overlay", toggle=True, text="", icon='RESTRICT_VIEW_OFF') + else: + row.prop(brush, "use_cursor_overlay", toggle=True, text="", icon='RESTRICT_VIEW_ON') + + sub = row.row() + sub.prop(brush, "cursor_overlay_alpha", text="Alpha") + sub.prop(brush, "cursor_overlay_override", toggle=True, text="", icon='BRUSH_DATA') + class VIEW3D_PT_tools_brush_texture(Panel, View3DPaintPanel): bl_label = "Texture" @@ -811,7 +851,7 @@ class VIEW3D_PT_tools_mask_texture(View3DPanel, Panel): row.prop(brush, "use_secondary_overlay", toggle=True, text="", icon='RESTRICT_VIEW_ON') sub = row.row() - sub.prop(brush, "texture_overlay_alpha", text="Alpha") + sub.prop(brush, "mask_overlay_alpha", text="Alpha") sub.prop(brush, "cursor_overlay_override", toggle=True, text="", icon='BRUSH_DATA') diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index ff5efd3b02b..5b53f1d34c9 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -79,7 +79,7 @@ void BKE_paint_invalidate_overlay_tex(struct Scene *scene, const struct Tex *tex void BKE_paint_invalidate_cursor_overlay(struct Scene *scene, struct CurveMapping *curve); void BKE_paint_invalidate_overlay_all(void); OverlayControlFlags BKE_paint_get_overlay_flags(void); -void BKE_paint_reset_overlay_invalid(void); +void BKE_paint_reset_overlay_invalid(OverlayControlFlags flag); void BKE_paint_set_overlay_override(bool flag); bool BKE_paint_get_overlay_override(void); diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 59bfb987a19..ef751d130db 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -108,11 +108,9 @@ bool BKE_paint_get_overlay_override(void) } -void BKE_paint_reset_overlay_invalid(void) +void BKE_paint_reset_overlay_invalid(OverlayControlFlags flag) { - overlay_flags &= ~(PAINT_INVALID_OVERLAY_TEXTURE_PRIMARY | - PAINT_INVALID_OVERLAY_TEXTURE_SECONDARY | - PAINT_INVALID_OVERLAY_CURVE); + overlay_flags &= ~(flag); } diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 7525085fd53..3770ff7b85d 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -69,9 +69,13 @@ */ typedef struct TexSnapshot { + GLuint overlay_texture; int winx; int winy; bool init; + int old_size; + int old_zoom; + bool old_col; } TexSnapshot; typedef struct CurveSnapshot { @@ -80,35 +84,35 @@ typedef struct CurveSnapshot { bool init; } CurveSnapshot; -static int same_tex_snap(TexSnapshot *snap, Brush *brush, ViewContext *vc) +static int same_tex_snap(TexSnapshot *snap, MTex *mtex, ViewContext *vc, bool col, float zoom) { - MTex *mtex = &brush->mtex; - return (/* make brush smaller shouldn't cause a resample */ //(mtex->brush_map_mode != MTEX_MAP_MODE_VIEW || //(BKE_brush_size_get(vc->scene, brush) <= snap->BKE_brush_size_get)) && (mtex->brush_map_mode != MTEX_MAP_MODE_TILED || (vc->ar->winx == snap->winx && - vc->ar->winy == snap->winy)) + vc->ar->winy == snap->winy)) && + snap->old_zoom == zoom && + snap->old_col == col ); } -static void make_tex_snap(TexSnapshot *snap, ViewContext *vc) +static void make_tex_snap(TexSnapshot *snap, ViewContext *vc, float zoom) { + snap->old_zoom = zoom; snap->winx = vc->ar->winx; snap->winy = vc->ar->winy; } -static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col) +static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool primary) { - static GLuint overlay_texture = 0; static int init = 0; - static TexSnapshot snap; - static int old_size = -1; - static int old_zoom = -1; - static bool old_col = -1; + static TexSnapshot primary_snap = {0}; + static TexSnapshot secondary_snap = {0}; + TexSnapshot *target; + MTex *mtex = (primary) ? &br->mtex : &br->mask_mtex; OverlayControlFlags overlay_flags = BKE_paint_get_overlay_flags(); GLubyte *buffer = NULL; @@ -116,29 +120,29 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col) int j; int refresh; GLenum format = col ? GL_RGBA : GL_ALPHA; + OverlayControlFlags invalid = (primary) ? (overlay_flags & PAINT_INVALID_OVERLAY_TEXTURE_PRIMARY) : + (overlay_flags & PAINT_INVALID_OVERLAY_TEXTURE_SECONDARY); + + target = (primary) ? &primary_snap : &secondary_snap; - if (br->mtex.brush_map_mode != MTEX_MAP_MODE_VIEW && !br->mtex.tex) return 0; + if (mtex->brush_map_mode != MTEX_MAP_MODE_VIEW && !mtex->tex) return 0; refresh = - !overlay_texture || - (overlay_flags & PAINT_INVALID_OVERLAY_TEXTURE_PRIMARY) || - (overlay_flags & PAINT_INVALID_OVERLAY_CURVE) || - old_zoom != zoom || - old_col != col || - !same_tex_snap(&snap, br, vc); + !target->overlay_texture || + (invalid != 0) || + !same_tex_snap(target, mtex, vc, col, zoom); if (refresh) { struct ImagePool *pool = NULL; /* stencil is rotated later */ - const float rotation = (br->mtex.brush_map_mode != MTEX_MAP_MODE_STENCIL) ? - -br->mtex.rot : 0; + const float rotation = (mtex->brush_map_mode != MTEX_MAP_MODE_STENCIL) ? + -mtex->rot : 0; float radius = BKE_brush_size_get(vc->scene, br) * zoom; - old_zoom = zoom; - make_tex_snap(&snap, vc); + make_tex_snap(target, vc, zoom); - if (br->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) { + if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) { int s = BKE_brush_size_get(vc->scene, br); int r = 1; @@ -150,32 +154,30 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col) if (size < 256) size = 256; - if (size < old_size) - size = old_size; + if (size < target->old_size) + size = target->old_size; } else size = 512; - if (old_size != size) { - if (overlay_texture) { - glDeleteTextures(1, &overlay_texture); - overlay_texture = 0; + if (target->old_size != size) { + if (target->overlay_texture) { + glDeleteTextures(1, &target->overlay_texture); + target->overlay_texture = 0; } init = 0; - old_size = size; + target->old_size = size; } if (col) buffer = MEM_mallocN(sizeof(GLubyte) * size * size * 4, "load_tex"); else buffer = MEM_mallocN(sizeof(GLubyte) * size * size, "load_tex"); - if (br->mtex.tex) + if (mtex->tex) pool = BKE_image_pool_new(); - curvemapping_initialize(br->curve); - #pragma omp parallel for schedule(static) for (j = 0; j < size; j++) { int i; @@ -192,7 +194,7 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col) x = (float)i / size; y = (float)j / size; - if (br->mtex.brush_map_mode == MTEX_MAP_MODE_TILED) { + if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) { x *= vc->ar->winx / radius; y *= vc->ar->winy / radius; } @@ -206,47 +208,39 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col) len = sqrtf(x * x + y * y); - if (ELEM(br->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL) || len <= 1) { + if (ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL) || len <= 1) { /* it is probably worth optimizing for those cases where * the texture is not rotated by skipping the calls to * atan2, sqrtf, sin, and cos. */ - if (br->mtex.tex && (rotation > 0.001f || rotation < -0.001f)) { - const float angle = atan2f(y, x) + rotation; + if (mtex->tex && (rotation > 0.001f || rotation < -0.001f)) { + const float angle = atan2f(y, x) + rotation; x = len * cosf(angle); y = len * sinf(angle); } - x *= br->mtex.size[0]; - y *= br->mtex.size[1]; + x *= mtex->size[0]; + y *= mtex->size[1]; - x += br->mtex.ofs[0]; - y += br->mtex.ofs[1]; + x += mtex->ofs[0]; + y += mtex->ofs[1]; if (col) { float rgba[4]; - if (br->mtex.tex) - paint_get_tex_pixel_col(&br->mtex, x, y, rgba, pool); + if (mtex->tex) + paint_get_tex_pixel_col(mtex, x, y, rgba, pool); - if (br->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) { - float curve_str = BKE_brush_curve_strength(br, len, 1.0f); - CLAMP(curve_str, 0.0f, 1.0f); - mul_v4_fl(rgba, curve_str); /* Falloff curve */ - } buffer[index * 4] = rgba[0] * 255; buffer[index * 4 + 1] = rgba[1] * 255; buffer[index * 4 + 2] = rgba[2] * 255; buffer[index * 4 + 3] = rgba[3] * 255; } else { - float avg = br->mtex.tex ? paint_get_tex_pixel(&br->mtex, x, y, pool) : 1; + float avg = mtex->tex ? paint_get_tex_pixel(mtex, x, y, pool) : 1; avg += br->texture_sample_bias; - if (br->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) - avg *= BKE_brush_curve_strength(br, len, 1.0f); /* Falloff curve */ - /* clamp to avoid precision overflow */ CLAMP(avg, 0.0f, 1.0f); buffer[index] = 255 - (GLubyte)(255 * avg); @@ -269,17 +263,17 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col) if (pool) BKE_image_pool_free(pool); - if (!overlay_texture) - glGenTextures(1, &overlay_texture); + if (!target->overlay_texture) + glGenTextures(1, &target->overlay_texture); } else { - size = old_size; + size = target->old_size; } - glBindTexture(GL_TEXTURE_2D, overlay_texture); + glBindTexture(GL_TEXTURE_2D, target->overlay_texture); if (refresh) { - if (!init || (old_col != col)) { + if (!init || (target->old_col != col)) { glTexImage2D(GL_TEXTURE_2D, 0, format, size, size, 0, format, GL_UNSIGNED_BYTE, buffer); init = 1; } @@ -290,7 +284,7 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col) if (buffer) MEM_freeN(buffer); - old_col = col; + target->old_col = col; } glEnable(GL_TEXTURE_2D); @@ -299,16 +293,154 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - if (br->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) { + if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); } - BKE_paint_reset_overlay_invalid(); + BKE_paint_reset_overlay_invalid(invalid); + + return 1; +} + +static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom) +{ + static GLuint overlay_texture = 0; + static int init = 0; + static int old_size = -1; + static int old_zoom = -1; + + OverlayControlFlags overlay_flags = BKE_paint_get_overlay_flags(); + GLubyte *buffer = NULL; + + int size; + int j; + int refresh; + + if (br->mtex.brush_map_mode != MTEX_MAP_MODE_VIEW && !br->mtex.tex) return 0; + + refresh = + !overlay_texture || + (overlay_flags & PAINT_INVALID_OVERLAY_CURVE) || + old_zoom != zoom; + + if (refresh) { + int s, r; + float radius; + + old_zoom = zoom; + + s = BKE_brush_size_get(vc->scene, br); + r = 1; + radius = s * zoom; + + for (s >>= 1; s > 0; s >>= 1) + r++; + + size = (1 << r); + + if (size < 256) + size = 256; + + if (size < old_size) + size = old_size; + + if (old_size != size) { + if (overlay_texture) { + glDeleteTextures(1, &overlay_texture); + overlay_texture = 0; + } + + init = 0; + + old_size = size; + } + buffer = MEM_mallocN(sizeof(GLubyte) * size * size, "load_tex"); + + curvemapping_initialize(br->curve); + + #pragma omp parallel for schedule(static) + for (j = 0; j < size; j++) { + int i; + float y; + float len; + + for (i = 0; i < size; i++) { + + // largely duplicated from tex_strength + + int index = j * size + i; + float x; + + x = (float)i / size; + y = (float)j / size; + + if (br->mtex.brush_map_mode == MTEX_MAP_MODE_TILED) { + x *= vc->ar->winx / radius; + y *= vc->ar->winy / radius; + } + else { + x -= 0.5f; + y -= 0.5f; + + x *= 2; + y *= 2; + } + + len = sqrtf(x * x + y * y); + + if (len <= 1) { + float avg = BKE_brush_curve_strength(br, len, 1.0f); /* Falloff curve */ + + /* clamp to avoid precision overflow */ + CLAMP(avg, 0.0f, 1.0f); + buffer[index] = 255 - (GLubyte)(255 * avg); + + } + else { + buffer[index] = 0; + } + } + } + + if (!overlay_texture) + glGenTextures(1, &overlay_texture); + } + else { + size = old_size; + } + + glBindTexture(GL_TEXTURE_2D, overlay_texture); + + if (refresh) { + if (!init) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, size, size, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buffer); + init = 1; + } + else { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, GL_ALPHA, GL_UNSIGNED_BYTE, buffer); + } + + if (buffer) + MEM_freeN(buffer); + } + + glEnable(GL_TEXTURE_2D); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + + BKE_paint_reset_overlay_invalid(PAINT_INVALID_OVERLAY_CURVE); return 1; } + + static int project_brush_radius(ViewContext *vc, float radius, const float location[3]) @@ -397,36 +529,25 @@ static int sculpt_get_brush_geometry(bContext *C, ViewContext *vc, /* Draw an overlay that shows what effect the brush's texture will * have on brush strength */ -/* TODO: sculpt only for now */ -static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush, - ViewContext *vc, int x, int y, float zoom, PaintMode mode) +static void paint_draw_tex_overlay(UnifiedPaintSettings *ups, Brush *brush, + ViewContext *vc, int x, int y, float zoom, bool col, bool primary) { rctf quad; - bool col; /* check for overlay mode */ - if (!((brush->mtex.brush_map_mode == MTEX_MAP_MODE_STENCIL && brush->mtex.tex) || - ((brush->overlay_flags & BRUSH_OVERLAY_PRIMARY) && - ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_TILED)))) + MTex *mtex = (primary) ? &brush->mtex : &brush->mask_mtex; + bool valid = (primary) ? (brush->overlay_flags & BRUSH_OVERLAY_PRIMARY) != 0 : + (brush->overlay_flags & BRUSH_OVERLAY_SECONDARY) != 0; + int overlay_alpha = (primary) ? brush->texture_overlay_alpha : brush->mask_overlay_alpha; + + if (!((mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL && mtex->tex) || + (valid && + ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_TILED)))) { return; } - col = ELEM3(mode, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D, PAINT_VERTEX) ? true: false; - /* save lots of GL state - * TODO: check on whether all of these are needed? */ - glPushAttrib(GL_COLOR_BUFFER_BIT | - GL_CURRENT_BIT | - GL_DEPTH_BUFFER_BIT | - GL_ENABLE_BIT | - GL_LINE_BIT | - GL_POLYGON_BIT | - GL_STENCIL_BUFFER_BIT | - GL_TRANSFORM_BIT | - GL_VIEWPORT_BIT | - GL_TEXTURE_BIT); - - if (load_tex(brush, vc, zoom, col)) { + if (load_tex(brush, vc, zoom, col, primary)) { glEnable(GL_BLEND); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); @@ -437,7 +558,7 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush, glPushMatrix(); glLoadIdentity(); - if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) { + if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) { /* brush rotation */ glTranslatef(0.5, 0.5, 0); glRotatef((double)RAD2DEGF(ups->brush_rotation), @@ -445,7 +566,7 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush, glTranslatef(-0.5f, -0.5f, 0); /* scale based on tablet pressure */ - if (ups->draw_pressure && BKE_brush_use_size_pressure(vc->scene, brush)) { + if (primary && ups->draw_pressure && BKE_brush_use_size_pressure(vc->scene, brush)) { glTranslatef(0.5f, 0.5f, 0); glScalef(1.0f / ups->pressure_value, 1.0f / ups->pressure_value, 1); glTranslatef(-0.5f, -0.5f, 0); @@ -466,7 +587,7 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush, quad.ymax = y + radius; } } - else if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_TILED) { + else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) { quad.xmin = 0; quad.ymin = 0; quad.xmax = BLI_rcti_size_x(&vc->ar->winrct); @@ -482,7 +603,7 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush, glMatrixMode(GL_MODELVIEW); glPushMatrix(); glTranslatef(brush->stencil_pos[0], brush->stencil_pos[1], 0); - glRotatef(RAD2DEGF(brush->mtex.rot), 0, 0, 1); + glRotatef(RAD2DEGF(mtex->rot), 0, 0, 1); glMatrixMode(GL_TEXTURE); } @@ -491,12 +612,12 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush, glColor4f(1.0, 1.0, 1.0, - brush->texture_overlay_alpha / 100.0f); + overlay_alpha / 100.0f); else glColor4f(U.sculpt_paint_overlay_col[0], U.sculpt_paint_overlay_col[1], U.sculpt_paint_overlay_col[2], - brush->texture_overlay_alpha / 100.0f); + overlay_alpha / 100.0f); /* draw textured quad */ glBegin(GL_QUADS); @@ -512,11 +633,103 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush, glPopMatrix(); - if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_STENCIL) { + if (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) { glMatrixMode(GL_MODELVIEW); glPopMatrix(); } } +} + +/* Draw an overlay that shows what effect the brush's texture will + * have on brush strength */ +static void paint_draw_cursor_overlay(UnifiedPaintSettings *ups, Brush *brush, + ViewContext *vc, int x, int y, float zoom) +{ + rctf quad; + /* check for overlay mode */ + + if (!(brush->overlay_flags & BRUSH_OVERLAY_CURSOR)) + { + return; + } + + if (load_tex_cursor(brush, vc, zoom)) { + glEnable(GL_BLEND); + + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glDepthMask(GL_FALSE); + glDepthFunc(GL_ALWAYS); + + /* scale based on tablet pressure */ + if (ups->draw_pressure && BKE_brush_use_size_pressure(vc->scene, brush)) { + glTranslatef(0.5f, 0.5f, 0); + glScalef(1.0f / ups->pressure_value, 1.0f / ups->pressure_value, 1); + glTranslatef(-0.5f, -0.5f, 0); + } + + if (ups->draw_anchored) { + const float *aim = ups->anchored_initial_mouse; + quad.xmin = aim[0] - ups->anchored_size; + quad.ymin = aim[1] - ups->anchored_size; + quad.xmax = aim[0] + ups->anchored_size; + quad.ymax = aim[1] + ups->anchored_size; + } + else { + const int radius = BKE_brush_size_get(vc->scene, brush) * zoom; + quad.xmin = x - radius; + quad.ymin = y - radius; + quad.xmax = x + radius; + quad.ymax = y + radius; + } + + glColor4f(U.sculpt_paint_overlay_col[0], + U.sculpt_paint_overlay_col[1], + U.sculpt_paint_overlay_col[2], + brush->cursor_overlay_alpha / 100.0f); + + /* draw textured quad */ + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2f(quad.xmin, quad.ymin); + glTexCoord2f(1, 0); + glVertex2f(quad.xmax, quad.ymin); + glTexCoord2f(1, 1); + glVertex2f(quad.xmax, quad.ymax); + glTexCoord2f(0, 1); + glVertex2f(quad.xmin, quad.ymax); + glEnd(); + } +} + +static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush, + ViewContext *vc, int x, int y, float zoom, PaintMode mode) +{ + /* color means that primary brush texture is colured and secondary is used for alpha/mask control */ + bool col = ELEM3(mode, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D, PAINT_VERTEX) ? true: false; + + /* save lots of GL state + * TODO: check on whether all of these are needed? */ + glPushAttrib(GL_COLOR_BUFFER_BIT | + GL_CURRENT_BIT | + GL_DEPTH_BUFFER_BIT | + GL_ENABLE_BIT | + GL_LINE_BIT | + GL_POLYGON_BIT | + GL_STENCIL_BUFFER_BIT | + GL_TRANSFORM_BIT | + GL_VIEWPORT_BIT | + GL_TEXTURE_BIT); + + + /* coloured overlay should be drawn separately */ + if (col) { + paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, true, true); + paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, false); + paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom); + } else { + paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, true); + paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom); + } glPopAttrib(); } diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 14330229aba..de3c4db3b60 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -3796,6 +3796,7 @@ static void *do_projectpaint_thread(void *ph_v) /* for smear only */ float pos_ofs[2] = {0}; float co[2]; + float texmask = 1.0; float mask = 1.0f; /* airbrush wont use mask */ unsigned short mask_short; const float radius = (float)BKE_brush_size_get(ps->scene, brush); @@ -3909,7 +3910,8 @@ static void *do_projectpaint_thread(void *ph_v) } if (ps->is_maskbrush) { - alpha *= BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool); + texmask = BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool); + alpha *= texmask; } if (!ps->do_masking) { @@ -3922,7 +3924,7 @@ static void *do_projectpaint_thread(void *ph_v) falloff = 1.0f - falloff; falloff = 1.0f - (falloff * falloff); - mask_short = (unsigned short)(projPixel->mask * (BKE_brush_alpha_get(ps->scene, brush) * falloff)); + mask_short = (unsigned short)(projPixel->mask * (BKE_brush_alpha_get(ps->scene, brush) * falloff)) * texmask; if (mask_short > projPixel->mask_max) { mask = ((float)mask_short) / 65535.0f; projPixel->mask_max = mask_short; diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index ef7fbec3742..4369c6dfabd 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -523,7 +523,7 @@ static void rna_def_brush_texture_slot(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "brush_map_mode"); RNA_def_property_enum_items(prop, prop_mask_paint_map_mode_items); RNA_def_property_ui_text(prop, "Mode", ""); - RNA_def_property_update(prop, 0, "rna_TextureSlot_update"); + RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update"); } static void rna_def_sculpt_capabilities(BlenderRNA *brna) |