diff options
author | Pablo Dobarro <pablodp606@gmail.com> | 2019-10-07 20:34:15 +0300 |
---|---|---|
committer | Pablo Dobarro <pablodp606@gmail.com> | 2019-10-07 20:47:40 +0300 |
commit | ce22efb4258ab254573d5672c2b939a320a60cb2 (patch) | |
tree | e41519e24630bac990154a10db2f602ff7bd3694 /source/blender/editors/sculpt_paint/paint_image_2d.c | |
parent | dccdc5df10fe357d8026afdcff43fcac82a9231d (diff) |
Paint: 2D paint brush stroke antialiasing
This commit enables antialiasing in 2D painting.
It also includes some fixes related to line drawing in the stroke spacing code.
Reviewed By: brecht
Differential Revision: https://developer.blender.org/D5833
Diffstat (limited to 'source/blender/editors/sculpt_paint/paint_image_2d.c')
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_image_2d.c | 73 |
1 files changed, 56 insertions, 17 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 4f1ae10aa62..9c95a3cee4d 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -374,25 +374,65 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter, /* create a mask with the falloff strength */ static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter, int diameter, - float radius) + float radius, + const float pos[2]) { Brush *brush = painter->brush; - int xoff = -radius; - int yoff = -radius; + int offset = (int)floorf(diameter / 2.0f); unsigned short *mask, *m; - int x, y; mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask"); m = mask; - for (y = 0; y < diameter; y++) { - for (x = 0; x < diameter; x++, m++) { - float xy[2] = {x + xoff, y + yoff}; - float len = len_v2(xy); + int aa_samples = 1.0f / (radius * 0.20f); + aa_samples = clamp_i(aa_samples, 3, 16); - *m = (unsigned short)(65535.0f * BKE_brush_curve_strength_clamped(brush, len, radius)); + /* Temporal until we have the brush properties */ + const float hardness = 1.0f; + const float rotation = 0.0f; + + float aa_offset = 1.0f / (2.0f * (float)aa_samples); + float aa_step = 1.0f / (float)aa_samples; + + float bpos[2]; + bpos[0] = pos[0] - floorf(pos[0]) + offset + aa_offset; + bpos[1] = pos[1] - floorf(pos[1]) + offset + aa_offset; + + const float co = cosf(DEG2RADF(rotation)); + const float si = sinf(DEG2RADF(rotation)); + + float norm_factor = 65535.0f / (float)(aa_samples * aa_samples); + + for (int y = 0; y < diameter; y++) { + for (int x = 0; x < diameter; x++, m++) { + float total_samples = 0; + for (int i = 0; i < aa_samples; i++) { + for (int j = 0; j < aa_samples; j++) { + float pixel_xy[2] = {x + (aa_step * i), y + (aa_step * j)}; + float xy_rot[2]; + sub_v2_v2(pixel_xy, bpos); + + xy_rot[0] = co * pixel_xy[0] - si * pixel_xy[1]; + xy_rot[1] = si * pixel_xy[0] + co * pixel_xy[1]; + + float len = len_v2(xy_rot); + float p = len / radius; + if (hardness < 1.0f) { + p = (p - hardness) / (1 - hardness); + p = 1.0f - p; + CLAMP(p, 0, 1); + } + else { + p = 1.0; + } + float hardness_factor = 3.0f * p * p - 2.0f * p * p * p; + float curve = BKE_brush_curve_strength_clamped(brush, len, radius); + total_samples += curve * hardness_factor; + } + } + *m = (unsigned short)(total_samples * norm_factor); } } @@ -721,7 +761,8 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s, UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; Brush *brush = painter->brush; BrushPainterCache *cache = &painter->cache; - const int diameter = 2 * size; + /* Adding 4 pixels of padding for brush antialiasing */ + const int diameter = MAX2(1, size * 2) + 4; bool do_random = false; bool do_partial_update = false; @@ -802,15 +843,13 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s, } /* curve mask can only change if the size changes */ - if (diameter != cache->lastdiameter) { - if (cache->curve_mask) { - MEM_freeN(cache->curve_mask); - cache->curve_mask = NULL; - } - - cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size); + if (cache->curve_mask) { + MEM_freeN(cache->curve_mask); + cache->curve_mask = NULL; } + cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size, pos); + /* detect if we need to recreate image brush buffer */ if ((diameter != cache->lastdiameter) || (tex_rotation != cache->last_tex_rotation) || do_random || update_color) { |