diff options
Diffstat (limited to 'source/blender/blenkernel/intern/brush.c')
-rw-r--r-- | source/blender/blenkernel/intern/brush.c | 205 |
1 files changed, 166 insertions, 39 deletions
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index ba69fa4336e..6adcdbd2c3e 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -53,6 +53,7 @@ #include "IMB_imbuf_types.h" #include "RE_render_ext.h" /* externtex */ +#include "RE_shader_ext.h" static void brush_defaults(Brush *brush) { @@ -471,62 +472,133 @@ int BKE_brush_clone_image_delete(Brush *brush) return 0; } -/* Brush Sampling for 3d brushes. Currently used for texture painting only, but should be generalized */ -void BKE_brush_sample_tex(const Scene *scene, Brush *brush, const float sampleco[3], float rgba[4], const int thread, struct ImagePool *pool) +/* Generic texture sampler for 3D painting systems. point has to be either in + * region space mouse coordinates, or 3d world coordinates for 3D mapping */ +float BKE_brush_sample_tex_3D(const Scene *scene, Brush *br, + const float point[3], + float rgba[4], const int thread, + struct ImagePool *pool) { - MTex *mtex = &brush->mtex; + UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; + MTex *mtex = &br->mtex; + float intensity = 1.0; + bool hasrgb = false; - if (mtex && mtex->tex) { - float tin, tr, tg, tb, ta; - int hasrgb; - const int radius = BKE_brush_size_get(scene, brush); + if (!mtex->tex) { + intensity = 1; + } + else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) { + /* Get strength by feeding the vertex + * location directly into a texture */ + hasrgb = externtex(mtex, point, &intensity, + rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool); + } + else { + float rotation = -mtex->rot; + float point_2d[2] = {point[0], point[1]}; + float x = 0.0f, y = 0.0f; /* Quite warnings */ + float radius = 1.0f; /* Quite warnings */ + float co[3]; - if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) { - hasrgb = externtex(mtex, sampleco, &tin, &tr, &tg, &tb, &ta, thread, pool); - } - else { - float co[3]; + if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) { + /* keep coordinates relative to mouse */ + + rotation += ups->brush_rotation; - co[0] = sampleco[0] / radius; - co[1] = sampleco[1] / radius; - co[2] = 0.0f; + point_2d[0] -= ups->tex_mouse[0]; + point_2d[1] -= ups->tex_mouse[1]; - hasrgb = externtex(mtex, co, &tin, &tr, &tg, &tb, &ta, thread, pool); + /* use pressure adjusted size for fixed mode */ + radius = ups->pixel_radius; + + x = point_2d[0]; + y = point_2d[1]; } + else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) { + /* leave the coordinates relative to the screen */ - if (hasrgb) { - rgba[0] = tr; - rgba[1] = tg; - rgba[2] = tb; - rgba[3] = ta; + /* use unadjusted size for tiled mode */ + radius = BKE_brush_size_get(scene, br); + + x = point_2d[0]; + y = point_2d[1]; } - else { - rgba[0] = tin; - rgba[1] = tin; - rgba[2] = tin; - rgba[3] = 1.0f; + + x /= radius; + y /= radius; + + /* 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 (rotation > 0.001f || rotation < -0.001f) { + const float angle = atan2f(y, x) + rotation; + const float flen = sqrtf(x * x + y * y); + + x = flen * cosf(angle); + y = flen * sinf(angle); } + + x *= br->mtex.size[0]; + y *= br->mtex.size[1]; + + co[0] = x + br->mtex.ofs[0]; + co[1] = y + br->mtex.ofs[1]; + co[2] = 0.0f; + + hasrgb = externtex(mtex, co, &intensity, + rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool); } - else { - rgba[0] = rgba[1] = rgba[2] = rgba[3] = 1.0f; + + intensity += br->texture_sample_bias; + + if (!hasrgb) { + rgba[0] = intensity; + rgba[1] = intensity; + rgba[2] = intensity; + rgba[3] = 1.0f; } + + return intensity; } + /* Brush Sampling for 2D brushes. when we unify the brush systems this will be necessarily a separate function */ -void BKE_brush_sample_tex_2D(const Scene *scene, Brush *brush, const float xy[2], float rgba[4], const int thread) +float BKE_brush_sample_tex_2D(const Scene *scene, Brush *brush, const float xy[2], float rgba[4], struct ImagePool *pool) { + UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; MTex *mtex = &brush->mtex; if (mtex && mtex->tex) { float co[3], tin, tr, tg, tb, ta; + float x = xy[0], y = xy[1]; int hasrgb; - const int radius = BKE_brush_size_get(scene, brush); + int radius = BKE_brush_size_get(scene, brush); + float rotation = -mtex->rot; + + if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) { + rotation += ups->brush_rotation; + radius = ups->pixel_radius; + } + + x /= radius; + y /= radius; + + if (rotation > 0.001f || rotation < -0.001f) { + const float angle = atan2f(y, x) + rotation; + const float flen = sqrtf(x * x + y * y); - co[0] = xy[0] / radius; - co[1] = xy[1] / radius; + x = flen * cosf(angle); + y = flen * sinf(angle); + } + + x *= brush->mtex.size[0]; + y *= brush->mtex.size[1]; + + co[0] = x + brush->mtex.ofs[0]; + co[1] = y + brush->mtex.ofs[1]; co[2] = 0.0f; - hasrgb = externtex(mtex, co, &tin, &tr, &tg, &tb, &ta, thread, NULL); + hasrgb = externtex(mtex, co, &tin, &tr, &tg, &tb, &ta, 0, pool); if (hasrgb) { rgba[0] = tr; @@ -540,9 +612,11 @@ void BKE_brush_sample_tex_2D(const Scene *scene, Brush *brush, const float xy[2] rgba[2] = tin; rgba[3] = 1.0f; } + return tin; } else { rgba[0] = rgba[1] = rgba[2] = rgba[3] = 1.0f; + return 1.0; } } @@ -790,7 +864,8 @@ void BKE_brush_scale_size(int *r_brush_size, void BKE_brush_jitter_pos(const Scene *scene, Brush *brush, const float pos[2], float jitterpos[2]) { - int use_jitter = brush->jitter != 0; + int use_jitter = (brush->flag & BRUSH_ABSOLUTE_JITTER) ? + (brush->jitter_absolute != 0) : (brush->jitter != 0); /* jitter-ed brush gives weird and unpredictable result for this * kinds of stroke, so manually disable jitter usage (sergey) */ @@ -798,17 +873,26 @@ void BKE_brush_jitter_pos(const Scene *scene, Brush *brush, const float pos[2], if (use_jitter) { float rand_pos[2]; - const int radius = BKE_brush_size_get(scene, brush); - const int diameter = 2 * radius; + float spread; + int diameter; - /* find random position within a circle of diameter 1 */ do { rand_pos[0] = BLI_frand() - 0.5f; rand_pos[1] = BLI_frand() - 0.5f; } while (len_v2(rand_pos) > 0.5f); - jitterpos[0] = pos[0] + 2 * rand_pos[0] * diameter * brush->jitter; - jitterpos[1] = pos[1] + 2 * rand_pos[1] * diameter * brush->jitter; + + if (brush->flag & BRUSH_ABSOLUTE_JITTER) { + diameter = 2 * brush->jitter_absolute; + spread = 1.0; + } + else { + diameter = 2 * BKE_brush_size_get(scene, brush); + spread = brush->jitter; + } + /* find random position within a circle of diameter 1 */ + jitterpos[0] = pos[0] + 2 * rand_pos[0] * diameter * spread; + jitterpos[1] = pos[1] + 2 * rand_pos[1] * diameter * spread; } else { copy_v2_v2(jitterpos, pos); @@ -841,6 +925,49 @@ float BKE_brush_curve_strength(Brush *br, float p, const float len) return curvemapping_evaluateF(br->curve, 0, p); } +/* TODO: should probably be unified with BrushPainter stuff? */ +unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side) +{ + unsigned int *texcache = NULL; + MTex *mtex = &br->mtex; + TexResult texres = {0}; + int hasrgb, ix, iy; + int side = half_side * 2; + + if (mtex->tex) { + float x, y, step = 2.0 / side, co[3]; + + texcache = MEM_callocN(sizeof(int) * side * side, "Brush texture cache"); + + /*do normalized cannonical view coords for texture*/ + for (y = -1.0, iy = 0; iy < side; iy++, y += step) { + for (x = -1.0, ix = 0; ix < side; ix++, x += step) { + co[0] = x; + co[1] = y; + co[2] = 0.0f; + + /* This is copied from displace modifier code */ + hasrgb = multitex_ext(mtex->tex, co, NULL, NULL, 0, &texres, NULL); + + /* if the texture gave an RGB value, we assume it didn't give a valid + * intensity, so calculate one (formula from do_material_tex). + * if the texture didn't give an RGB value, copy the intensity across + */ + if (hasrgb & TEX_RGB) + texres.tin = rgb_to_grayscale(&texres.tr); + + ((char *)texcache)[(iy * side + ix) * 4] = + ((char *)texcache)[(iy * side + ix) * 4 + 1] = + ((char *)texcache)[(iy * side + ix) * 4 + 2] = + ((char *)texcache)[(iy * side + ix) * 4 + 3] = (char)(texres.tin * 255.0f); + } + } + } + + return texcache; +} + + /**** Radial Control ****/ struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br) { |