diff options
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 111 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_texture_types.h | 1 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_brush.c | 16 |
3 files changed, 115 insertions, 13 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 4c19f3ce93e..a124afddc8e 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -253,6 +253,10 @@ typedef struct StrokeCache { transforms */ float sculpt_normal[3]; float sculpt_normal_symm[3]; + + /* Used for wrap texture mode, local_mat gets calculated by + calc_brush_local_mat() and used in tex_strength(). */ + float brush_local_mat[4][4]; float last_center[3]; int radial_symmetry_pass; @@ -786,17 +790,31 @@ static float tex_strength(SculptSession *ss, Brush *br, float point[3], x = point_2d[0]; y = point_2d[1]; } + else if (mtex->brush_map_mode == MTEX_MAP_MODE_AREA) { + /* Similar to fixed mode, but projects from brush angle + rather than view direction */ + + /* Rotation is handled by the brush_local_mat */ + rotation = 0; - x /= ss->cache->vc->ar->winx; - y /= ss->cache->vc->ar->winy; + mul_m4_v3(ss->cache->brush_local_mat, symm_point); - if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) { - x -= 0.5f; - y -= 0.5f; + x = symm_point[0]; + y = symm_point[1]; } + + if (mtex->brush_map_mode != MTEX_MAP_MODE_AREA) { + x /= ss->cache->vc->ar->winx; + y /= ss->cache->vc->ar->winy; + + if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) { + x -= 0.5f; + y -= 0.5f; + } - x *= ss->cache->vc->ar->winx / radius; - y *= ss->cache->vc->ar->winy / radius; + x *= ss->cache->vc->ar->winx / radius; + y *= ss->cache->vc->ar->winy / radius; + } /* it is probably worth optimizing for those cases where * the texture is not rotated by skipping the calls to @@ -1021,6 +1039,78 @@ static void update_sculpt_normal(Sculpt *sd, Object *ob, } } +static void calc_local_y(ViewContext *vc, const float center[3], float y[3]) +{ + Object *ob = vc->obact; + float loc[3], mval_f[2] = {0.0f, 1.0f}; + + mul_v3_m4v3(loc, ob->imat, center); + initgrabz(vc->rv3d, loc[0], loc[1], loc[2]); + + ED_view3d_win_to_delta(vc->ar, mval_f, y); + normalize_v3(y); + + add_v3_v3(y, ob->loc); + mul_m4_v3(ob->imat, y); +} + +static void calc_brush_local_mat(const Brush *brush, Object *ob, + float local_mat[4][4]) +{ + const StrokeCache *cache = ob->sculpt->cache; + float tmat[4][4]; + float mat[4][4]; + float scale[4][4]; + float angle, v[3]; + float up[3]; + + /* Ensure ob->imat is up to date */ + invert_m4_m4(ob->imat, ob->obmat); + + /* Initialize last column of matrix */ + mat[0][3] = 0; + mat[1][3] = 0; + mat[2][3] = 0; + mat[3][3] = 1; + + /* Get view's up vector in object-space */ + calc_local_y(cache->vc, cache->location, up); + + /* Calculate the X axis of the local matrix */ + cross_v3_v3v3(v, up, cache->sculpt_normal); + /* Apply rotation (user angle, rake, etc.) to X axis */ + angle = brush->mtex.rot - cache->special_rotation; + rotate_v3_v3v3fl(mat[0], v, cache->sculpt_normal, angle); + + /* Get other axes */ + cross_v3_v3v3(mat[1], cache->sculpt_normal, mat[0]); + copy_v3_v3(mat[2], cache->sculpt_normal); + + /* Set location */ + copy_v3_v3(mat[3], cache->location); + + /* Scale by brush radius */ + normalize_m4(mat); + scale_m4_fl(scale, cache->radius); + mult_m4_m4m4(tmat, mat, scale); + + /* Return inverse (for converting from modelspace coords to local + area coords) */ + invert_m4_m4(local_mat, tmat); +} + +static void update_brush_local_mat(Sculpt *sd, Object *ob) +{ + StrokeCache *cache = ob->sculpt->cache; + + if (cache->mirror_symmetry_pass == 0 && + cache->radial_symmetry_pass == 0) + { + calc_brush_local_mat(paint_brush(&sd->paint), ob, + cache->brush_local_mat); + } +} + /* Test whether the StrokeCache.sculpt_normal needs update in do_brush_action() */ static int brush_needs_sculpt_normal(const Brush *brush) @@ -1038,7 +1128,9 @@ static int brush_needs_sculpt_normal(const Brush *brush) SCULPT_TOOL_LAYER, SCULPT_TOOL_NUDGE, SCULPT_TOOL_ROTATE, - SCULPT_TOOL_THUMB)); + SCULPT_TOOL_THUMB) || + + (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)); } /* For the smooth brush, uses the neighboring vertices around vert to calculate @@ -2621,6 +2713,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush) if (brush_needs_sculpt_normal(brush)) update_sculpt_normal(sd, ob, nodes, totnode); + if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA) + update_brush_local_mat(sd, ob); + /* Apply one type of brush action */ switch (brush->sculpt_tool) { case SCULPT_TOOL_DRAW: diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index 413c3502c7e..7497f5e7449 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -520,6 +520,7 @@ typedef struct ColorMapping { #define MTEX_MAP_MODE_VIEW 0 #define MTEX_MAP_MODE_TILED 1 #define MTEX_MAP_MODE_3D 2 +#define MTEX_MAP_MODE_AREA 3 /* **************** EnvMap ********************* */ diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 0a8c241f5ee..2247e7cf5a8 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -172,7 +172,9 @@ static int rna_SculptCapabilities_has_plane_offset_get(PointerRNA *ptr) static int rna_SculptCapabilities_has_random_texture_angle_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return ((br->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) && + return (ELEM(br->mtex.brush_map_mode, + MTEX_MAP_MODE_VIEW, + MTEX_MAP_MODE_AREA) && !(br->flag & BRUSH_ANCHORED) && !ELEM4(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, @@ -233,15 +235,18 @@ static int rna_SculptCapabilities_has_strength_get(PointerRNA *ptr) static int rna_SculptCapabilities_has_texture_angle_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return ELEM(br->mtex.brush_map_mode, - MTEX_MAP_MODE_VIEW, - MTEX_MAP_MODE_TILED); + return ELEM3(br->mtex.brush_map_mode, + MTEX_MAP_MODE_VIEW, + MTEX_MAP_MODE_AREA, + MTEX_MAP_MODE_TILED); } static int rna_SculptCapabilities_has_texture_angle_source_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return br->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW; + return ELEM(br->mtex.brush_map_mode, + MTEX_MAP_MODE_VIEW, + MTEX_MAP_MODE_AREA); } static PointerRNA rna_Brush_sculpt_capabilities_get(PointerRNA *ptr) @@ -416,6 +421,7 @@ static void rna_def_brush_texture_slot(BlenderRNA *brna) static EnumPropertyItem prop_map_mode_items[] = { {MTEX_MAP_MODE_VIEW, "VIEW_PLANE", 0, "View Plane", ""}, + {MTEX_MAP_MODE_AREA, "AREA_PLANE", 0, "Area Plane", ""}, {MTEX_MAP_MODE_TILED, "TILED", 0, "Tiled", ""}, {MTEX_MAP_MODE_3D, "3D", 0, "3D", ""}, {0, NULL, 0, NULL, NULL} |