Texture sampling function refactoring:
authorAntony Riakiotakis <kalast@gmail.com>
Wed, 13 Mar 2013 03:46:22 +0000 (03:46 +0000)
committerAntony Riakiotakis <kalast@gmail.com>
Wed, 13 Mar 2013 03:46:22 +0000 (03:46 +0000)
ALERT! POSSIBLE BREAKING COMMIT, ESPECIALLY FOR SCULPT!

Separate the sculpt sampling function so that it can be reused
from other paint systems. This includes updating of the relevant
coordinates for anchored and rake style brushes, which are now
being updated as part of the stroke system.

I left only code for area-style brush texture mapping in sculpt
code, since it requires a few data structures not present on other
paint systems.

This commit makes it almost as easy to support rake on other systems as
exposing the python UI for it. Also it makes it totally possible to
have texture painting capabilities in vertex paint too :) These commits
will follow very soon.

Also, even if I did my best to keep the code from breaking, (even fixed a
leftover bug from coordinate changes) this is a big change. Please test!

source/blender/blenkernel/BKE_brush.h
source/blender/blenkernel/BKE_paint.h
source/blender/blenkernel/intern/brush.c
source/blender/blenkernel/intern/paint.c
source/blender/editors/sculpt_paint/paint_cursor.c
source/blender/editors/sculpt_paint/paint_image_2d.c
source/blender/editors/sculpt_paint/paint_intern.h
source/blender/editors/sculpt_paint/paint_stroke.c
source/blender/editors/sculpt_paint/sculpt.c
source/blender/makesdna/DNA_scene_types.h

index 3c65cb03c6860062015df701ab316bd5c7ba467d..2247495ce9e00cd3e3023109e5347f8ae99bbd9f 100644 (file)
@@ -70,7 +70,9 @@ float BKE_brush_curve_strength(struct Brush *br, float p, const float len); /* u
 
 /* sampling */
 void BKE_brush_sample_tex(const struct Scene *scene, struct Brush *brush, const float sampleco[3], float rgba[4], const int thread, struct ImagePool *pool);
-void BKE_brush_sample_tex_2D(const struct Scene *scene, struct Brush *brush, const float xy[2], float rgba[4], const int thread);
+float BKE_brush_sample_tex_3D(const Scene *scene, struct Brush *br,const float point[3],
+                               float rgba[3], struct ImagePool *pool);
+float BKE_brush_sample_tex_2D(const struct Scene *scene, struct Brush *brush, const float xy[2], float rgba[4], struct ImagePool *pool);
 void BKE_brush_imbuf_new(const struct Scene *scene, struct Brush *brush, short flt, short texfalloff, int size,
                          struct ImBuf **imbuf, int use_color_correction);
 
index 6e9dfdb5cbaf27f74bcd789d8d9866fc77be4ca4..35941d0a05a1ee8847d03be7a5c5a99c60ec82e2 100644 (file)
@@ -48,6 +48,7 @@ struct PBVH;
 struct Scene;
 struct StrokeCache;
 struct ImagePool;
+struct UnifiedPaintSettings;
 
 extern const char PAINT_CURSOR_SCULPT[3];
 extern const char PAINT_CURSOR_VERTEX_PAINT[3];
@@ -90,7 +91,7 @@ int paint_is_bmesh_face_hidden(struct BMFace *f);
 /* paint masks */
 float paint_grid_paint_mask(const struct GridPaintMask *gpm, unsigned level,
                             unsigned x, unsigned y);
-
+void paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups, const float mouse_pos[2]);
 /* Session data (mode-specific) */
 
 typedef struct SculptSession {
index ab821ec37a195827c84973a78e2920f24e06442c..4ec20d5fe0436257d9b183fc9bee319f0e1430d2 100644 (file)
@@ -513,8 +513,98 @@ void BKE_brush_sample_tex(const Scene *scene, Brush *brush, const float sampleco
        }
 }
 
+
+/* Return a multiplier for brush strength on a particular vertex. */
+float BKE_brush_sample_tex_3D(const Scene *scene, Brush *br,
+                          const float point[3],
+                                                 float rgba[3],
+                          struct ImagePool *pool)
+{
+       UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+       MTex *mtex = &br->mtex;
+       float intensity = 1.0;
+       bool hasrgb = false;
+
+       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, 0, 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[2];
+
+               if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
+                       /* keep coordinates relative to mouse */
+
+                       rotation += ups->brush_rotation;
+
+                       point_2d[0] -= ups->tex_mouse[0];
+                       point_2d[1] -= ups->tex_mouse[1];
+
+                       /* 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 */
+
+                       /* use unadjusted size for tiled mode */
+                       radius = BKE_brush_size_get(scene, br);
+
+                       x = point_2d[0];
+                       y = point_2d[1];
+               }
+
+               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, 0, pool);
+       }
+
+       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)
 {
        MTex *mtex = &brush->mtex;
 
@@ -527,7 +617,7 @@ void BKE_brush_sample_tex_2D(const Scene *scene, Brush *brush, const float xy[2]
                co[1] = xy[1] / radius;
                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;
@@ -541,9 +631,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;
        }
 }
 
index a001a13d000ca8d91faf08ffd88f16c64dcfcb72..cc647a90c8f2e4f7e8502b6f149d9d5fac040520 100644 (file)
@@ -40,6 +40,7 @@
 
 #include "BLI_bitmap.h"
 #include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
 
 #include "BKE_brush.h"
 #include "BKE_context.h"
@@ -300,3 +301,22 @@ float paint_grid_paint_mask(const GridPaintMask *gpm, unsigned level,
        
        return gpm->data[(y * factor) * gridsize + (x * factor)];
 }
+
+/* threshhold to move before updating the brush rotation */
+#define RAKE_THRESHHOLD 20
+
+void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, const float mouse_pos[2])
+{
+       const float u = 0.5f;
+       const float r = RAKE_THRESHHOLD;
+
+       float dpos[2];
+       sub_v2_v2v2(dpos, ups->last_rake, mouse_pos);
+
+       if (len_squared_v2(dpos) >= r * r) {
+               ups->brush_rotation = atan2(dpos[0], dpos[1]);
+
+               interp_v2_v2v2(ups->last_rake, ups->last_rake,
+                              mouse_pos, u);
+       }
+}
index bf6ad32efc195c1b7d5bdb13e13ed79dfa49586e..8d9cbbbcf111bf89dd2d870917fff73e5e379451 100644 (file)
@@ -207,14 +207,14 @@ static int load_tex(Brush *br, ViewContext *vc)
                                x = (float)i / size;
                                y = (float)j / size;
 
-                               x -= 0.5f;
-                               y -= 0.5f;
-
                                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;
                                }
@@ -420,8 +420,7 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush,
                if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
                        /* brush rotation */
                        glTranslatef(0.5, 0.5, 0);
-                       glRotatef((double)RAD2DEGF((brush->flag & BRUSH_RAKE) ?
-                                                  ups->last_angle : ups->special_rotation),
+                       glRotatef((double)RAD2DEGF(ups->brush_rotation),
                                  0.0, 0.0, 1.0);
                        glTranslatef(-0.5f, -0.5f, 0);
 
@@ -434,11 +433,10 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush,
 
                        if (ups->draw_anchored) {
                                const float *aim = ups->anchored_initial_mouse;
-                               const rcti *win = &vc->ar->winrct;
-                               quad.xmin = aim[0] - ups->anchored_size - win->xmin;
-                               quad.ymin = aim[1] - ups->anchored_size - win->ymin;
-                               quad.xmax = aim[0] + ups->anchored_size - win->xmin;
-                               quad.ymax = aim[1] + ups->anchored_size - win->ymin;
+                               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);
@@ -537,38 +535,22 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
         * mouse over too, not just during a stroke */
        view3d_set_viewcontext(C, &vc);
 
+       if (brush->flag & BRUSH_RAKE)
+               /* here, translation contains the mouse coordinates. */
+               paint_calculate_rake_rotation(ups, translation);
+
+       /* draw overlay */
+       paint_draw_alpha_overlay(ups, brush, &vc, x, y);
+
        /* TODO: as sculpt and other paint modes are unified, this
         * special mode of drawing will go away */
        if (vc.obact->sculpt) {
                float location[3];
                int pixel_radius, hit;
 
-               /* this is probably here so that rake takes into
-                * account the brush movements before the stroke
-                * starts, but this doesn't really belong in draw code
-                *  TODO) */
-               {
-                       const float u = 0.5f;
-                       const float v = 1 - u;
-                       const float r = 20;
-
-                       const float dx = ups->last_x - x;
-                       const float dy = ups->last_y - y;
-
-                       if (dx * dx + dy * dy >= r * r) {
-                               ups->last_angle = atan2(dx, dy);
-
-                               ups->last_x = u * ups->last_x + v * x;
-                               ups->last_y = u * ups->last_y + v * y;
-                       }
-               }
-
                /* test if brush is over the mesh */
                hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location);
 
-               /* draw overlay */
-               paint_draw_alpha_overlay(ups, brush, &vc, x, y);
-
                if (BKE_brush_use_locked_size(scene, brush))
                        BKE_brush_size_set(scene, brush, pixel_radius);
 
index 6c512d1cec83ca5f55bd0937699ab4edaa0f41f2..e2e448646b26c5c456df06ba16107896d77cac9a 100644 (file)
@@ -234,7 +234,7 @@ static void brush_painter_2d_do_partial(BrushPainter *painter, ImBuf *oldtexibuf
                                        xy[0] = x + xoff;
                                        xy[1] = y + yoff;
 
-                                       BKE_brush_sample_tex_2D(scene, brush, xy, tf, 0);
+                                       BKE_brush_sample_tex_2D(scene, brush, xy, tf, NULL);
                                }
 
                                bf[0] = tf[0] * mf[0];
@@ -265,7 +265,7 @@ static void brush_painter_2d_do_partial(BrushPainter *painter, ImBuf *oldtexibuf
                                        xy[0] = x + xoff;
                                        xy[1] = y + yoff;
 
-                                       BKE_brush_sample_tex_2D(scene, brush, xy, rgba, 0);
+                                       BKE_brush_sample_tex_2D(scene, brush, xy, rgba, NULL);
                                        rgba_float_to_uchar(t, rgba);
                                }
 
index 8d1076479cd8f32645343fbddcfb265d29a796f5..5371f644bcbffcc43c18c4bfac85d909173a35cc 100644 (file)
@@ -64,8 +64,9 @@ struct PaintStroke *paint_stroke_new(struct bContext *C,
                                      StrokeUpdateStep update_step, StrokeDone done, int event_type);
 void paint_stroke_data_free(struct wmOperator *op);
 
-bool paint_space_stroke_enabled(struct Brush *br);
-bool paint_supports_dynamic_size(struct Brush *br);
+bool paint_space_stroke_enabled(struct Brush *br, enum PaintMode mode);
+bool paint_supports_dynamic_size(struct Brush *br, enum PaintMode mode);
+bool paint_supports_moving_texture(struct Brush *br, enum PaintMode mode);
 bool paint_supports_jitter(enum PaintMode mode);
 
 struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf);
index 244b5f6b6fb5e101606a3424dd05dd0e3a9de5ab..a7e97e55ca6c1c48a0724ae15f8011d717624064 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "BLI_math.h"
 #include "BLI_utildefines.h"
+#include "BLI_rand.h"
 
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
@@ -91,6 +92,10 @@ typedef struct PaintStroke {
        /* event that started stroke, for modal() return */
        int event_type;
        
+       bool brush_init;
+       float initial_mouse[2];
+       float cached_pressure;
+
        StrokeGetLocation get_location;
        StrokeTestStart test_start;
        StrokeUpdateStep update_step;
@@ -136,6 +141,98 @@ static float event_tablet_data(wmEvent *event, int *pen_flip)
        return pressure;
 }
 
+#if 1
+/* Initialize the stroke cache variants from operator properties */
+static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode,
+                                         struct PaintStroke *stroke,
+                                         float mouse[2], float pressure)
+{
+       Scene *scene = CTX_data_scene(C);
+       UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+
+       /* XXX: Use pressure value from first brush step for brushes which don't
+        *      support strokes (grab, thumb). They depends on initial state and
+        *      brush coord/pressure/etc.
+        *      It's more an events design issue, which doesn't split coordinate/pressure/angle
+        *      changing events. We should avoid this after events system re-design */
+       if (paint_supports_dynamic_size(brush, mode) || !stroke->brush_init) {
+               copy_v2_v2(stroke->initial_mouse, mouse);
+               copy_v2_v2(ups->tex_mouse, mouse);
+               stroke->cached_pressure = pressure;
+       }
+
+       /* Truly temporary data that isn't stored in properties */
+
+       ups->draw_pressure = TRUE;
+       ups->pressure_value = stroke->cached_pressure;
+
+       ups->pixel_radius = BKE_brush_size_get(scene, brush);
+
+       if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, mode)) {
+               ups->pixel_radius *= stroke->cached_pressure;
+       }
+
+       if (!(brush->flag & BRUSH_ANCHORED ||
+             ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK,
+                   SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE)))
+       {
+               copy_v2_v2(ups->tex_mouse, mouse);
+
+               if ((brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) &&
+                   (brush->flag & BRUSH_RANDOM_ROTATION) &&
+                   !(brush->flag & BRUSH_RAKE))
+               {
+                       ups->brush_rotation = 2.0f * (float)M_PI * BLI_frand();
+               }
+       }
+
+       if (brush->flag & BRUSH_ANCHORED) {
+               bool hit = false;
+               float halfway[2];
+
+               const float dx = mouse[0] - stroke->initial_mouse[0];
+               const float dy = mouse[1] - stroke->initial_mouse[1];
+
+               ups->anchored_size = ups->pixel_radius = sqrt(dx * dx + dy * dy);
+
+               ups->brush_rotation = atan2(dx, dy) + M_PI;
+
+               if (brush->flag & BRUSH_EDGE_TO_EDGE) {
+                       float out[3];
+
+                       halfway[0] = dx * 0.5f + stroke->initial_mouse[0];
+                       halfway[1] = dy * 0.5f + stroke->initial_mouse[1];
+
+                       if (stroke->get_location) {
+                               if(stroke->get_location(C, out, halfway)) {
+                                       hit = true;
+                               }
+                       } else {
+                               hit = true;
+                       }
+               }
+               if(hit) {
+                       copy_v2_v2(ups->anchored_initial_mouse, halfway);
+                       copy_v2_v2(ups->tex_mouse, halfway);
+                       ups->anchored_size /= 2.0f;
+                       ups->pixel_radius  /= 2.0f;
+               }
+               else
+                       copy_v2_v2(ups->anchored_initial_mouse, stroke->initial_mouse);
+
+               ups->draw_anchored = 1;
+       }
+       else if (brush->flag & BRUSH_RAKE) {
+               if (!stroke->brush_init)
+                       copy_v2_v2(ups->last_rake, mouse);
+               else
+                       paint_calculate_rake_rotation(ups, mouse);
+       }
+
+       stroke->brush_init = TRUE;
+}
+#endif
+
 /* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */
 static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, const float mouse_in[2])
 {
@@ -199,6 +296,8 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *ev
        else
                zero_v3(location);
 
+       paint_brush_update(C, brush, mode, stroke, mouse_out, pressure);
+
        /* Add to stroke */
        RNA_collection_add(op->ptr, "stroke", &itemptr);
 
@@ -247,9 +346,11 @@ static int paint_smooth_stroke(PaintStroke *stroke, float output[2],
 static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const float final_mouse[2])
 {
        PaintStroke *stroke = op->customdata;
+       PaintMode mode = paintmode_get_active_from_context(C);
+
        int cnt = 0;
 
-       if (paint_space_stroke_enabled(stroke->brush)) {
+       if (paint_space_stroke_enabled(stroke->brush, mode)) {
                float mouse[2];
                float vec[2];
                float length, scale;
@@ -355,16 +456,41 @@ static void stroke_done(struct bContext *C, struct wmOperator *op)
 }
 
 /* Returns zero if the stroke dots should not be spaced, non-zero otherwise */
-bool paint_space_stroke_enabled(Brush *br)
+bool paint_space_stroke_enabled(Brush *br, PaintMode mode)
 {
-       return (br->flag & BRUSH_SPACE) && paint_supports_dynamic_size(br);
+       return (br->flag & BRUSH_SPACE) && paint_supports_dynamic_size(br, mode);
 }
 
 /* return true if the brush size can change during paint (normally used for pressure) */
-bool paint_supports_dynamic_size(Brush *br)
+bool paint_supports_dynamic_size(Brush *br, PaintMode mode)
 {
-       return !(br->flag & BRUSH_ANCHORED) &&
-              !ELEM4(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK);
+       if(br->flag & BRUSH_ANCHORED)
+               return false;
+
+       switch(mode) {
+               case PAINT_SCULPT:
+              if(ELEM4(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK))
+                       return false;
+               default:
+                       ;
+               }
+       return true;
+}
+
+/* return true if the brush size can change during paint (normally used for pressure) */
+bool paint_supports_moving_texture(Brush *br, PaintMode mode)
+{
+       if(br->flag & BRUSH_ANCHORED)
+               return false;
+
+       switch(mode) {
+               case PAINT_SCULPT:
+              if(ELEM4(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK))
+                       return false;
+               default:
+                       ;
+               }
+       return true;
 }
 
 bool paint_supports_jitter(PaintMode mode)
@@ -439,6 +565,7 @@ static void paint_stroke_sample_average(const PaintStroke *stroke,
 int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
 {
        Paint *p = paint_get_active_from_context(C);
+       PaintMode mode = paintmode_get_active_from_context(C);
        PaintStroke *stroke = op->customdata;
        PaintSample sample_average;
        float mouse[2];
@@ -489,7 +616,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
        {
                if (stroke->stroke_started) {
                        if (paint_smooth_stroke(stroke, mouse, &sample_average)) {
-                               if (paint_space_stroke_enabled(stroke->brush)) {
+                               if (paint_space_stroke_enabled(stroke->brush, mode)) {
                                        if (!paint_space_stroke(C, op, event, mouse)) {
                                                //ED_region_tag_redraw(ar);
                                        }
@@ -508,7 +635,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
         * instead of waiting till we have moved the space distance */
        if (first &&
            stroke->stroke_started &&
-           paint_space_stroke_enabled(stroke->brush) &&
+           paint_space_stroke_enabled(stroke->brush, mode) &&
            !(stroke->brush->flag & BRUSH_ANCHORED) &&
            !(stroke->brush->flag & BRUSH_SMOOTH_STROKE))
        {
index a43944f6609deed592d91a5faa48992876c89a92..7a6096b32d48090d62a66668132e5f58228019e1 100644 (file)
@@ -245,7 +245,6 @@ typedef struct StrokeCache {
        float pressure;
        float mouse[2];
        float bstrength;
-       float tex_mouse[2];
 
        /* The rest is temporary storage that isn't saved as a property */
 
@@ -259,8 +258,8 @@ typedef struct StrokeCache {
        Brush *brush;
 
        float (*face_norms)[3]; /* Copy of the mesh faces' normals */
-       float special_rotation; /* Texture rotation (radians) for anchored and rake modes */
-       int pixel_radius, previous_pixel_radius;
+
+       float special_rotation;
        float grab_delta[3], grab_delta_symmetry[3];
        float old_grab_location[3], orig_grab_location[3];
 
@@ -284,8 +283,8 @@ typedef struct StrokeCache {
        int radial_symmetry_pass;
        float symm_rot_mat[4][4];
        float symm_rot_mat_inv[4][4];
-       float last_rake[2]; /* Last location of updating rake rotation */
        int original;
+       float anchored_location[3];
 
        float vertex_rotation;
 
@@ -924,25 +923,22 @@ static float tex_strength(SculptSession *ss, Brush *br,
                           const float fno[3],
                           const float mask)
 {
+       const Scene *scene = ss->cache->vc->scene;
        MTex *mtex = &br->mtex;
        float avg = 1;
+       float rgba[4];
 
        if (!mtex->tex) {
                avg = 1;
        }
        else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
-               float jnk;
-
                /* Get strength by feeding the vertex 
                 * location directly into a texture */
-               externtex(mtex, point, &avg,
-                         &jnk, &jnk, &jnk, &jnk, 0, ss->tex_pool);
+               avg = BKE_brush_sample_tex_3D(scene, br, point, rgba, ss->tex_pool);
        }
        else if (ss->texcache) {
-               float rotation = -mtex->rot;
                float symm_point[3], point_2d[2];
                float x = 0.0f, y = 0.0f; /* Quite warnings */
-               float radius = 1.0f; /* Quite warnings */
 
                /* if the active area is being applied for symmetry, flip it
                 * across the symmetry axis and rotate it back to the original
@@ -956,77 +952,31 @@ static float tex_strength(SculptSession *ss, Brush *br,
 
                ED_view3d_project_float_v2_m4(ss->cache->vc->ar, symm_point, point_2d, ss->cache->projection_mat);
 
-               if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
-                       /* keep coordinates relative to mouse */
-
-                       rotation += ss->cache->special_rotation;
-
-                       point_2d[0] -= ss->cache->tex_mouse[0];
-                       point_2d[1] -= ss->cache->tex_mouse[1];
-
-                       /* use pressure adjusted size for fixed mode */
-                       radius = ss->cache->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 */
-
-                       /* use unadjusted size for tiled mode */
-                       radius = BKE_brush_size_get(ss->cache->vc->scene, br);
-               
-                       x = point_2d[0];
-                       y = point_2d[1];
-               }
-               else if (mtex->brush_map_mode == MTEX_MAP_MODE_AREA) {
+               /* still no symmetry supported for other paint modes.
+                * Sculpt does it DIY */
+               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;
-
                        mul_m4_v3(ss->cache->brush_local_mat, symm_point);
 
                        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;
+                       x *= br->mtex.size[0];
+                       y *= br->mtex.size[1];
 
-                       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 += br->mtex.ofs[0];
+                       y += br->mtex.ofs[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 (rotation > 0.001f || rotation < -0.001f) {
-                       const float angle    = atan2f(y, x) + rotation;
-                       const float flen     = sqrtf(x * x + y * y);
+                       avg = paint_get_tex_pixel(br, x, y, ss->tex_pool);
 
-                       x = flen * cosf(angle);
-                       y = flen * sinf(angle);
+                       avg += br->texture_sample_bias;
+               } else {
+                       avg = BKE_brush_sample_tex_3D(scene, br, point_2d, rgba, ss->tex_pool);
                }
-
-               x *= br->mtex.size[0];
-               y *= br->mtex.size[1];
-
-               x += br->mtex.ofs[0];
-               y += br->mtex.ofs[1];
-
-               avg = paint_get_tex_pixel(br, x, y, ss->tex_pool);
        }
 
-       avg += br->texture_sample_bias;
-
        /* Falloff curve */
        avg *= BKE_brush_curve_strength(br, len, ss->cache->radius);
 
@@ -3716,21 +3666,21 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
        ss->cache = cache;
 
        /* Set scaling adjustment */
-       ss->cache->scale[0] = 1.0f / ob->size[0];
-       ss->cache->scale[1] = 1.0f / ob->size[1];
-       ss->cache->scale[2] = 1.0f / ob->size[2];
+       cache->scale[0] = 1.0f / ob->size[0];
+       cache->scale[1] = 1.0f / ob->size[1];
+       cache->scale[2] = 1.0f / ob->size[2];
 
-       ss->cache->plane_trim_squared = brush->plane_trim * brush->plane_trim;
+       cache->plane_trim_squared = brush->plane_trim * brush->plane_trim;
 
-       ss->cache->flag = 0;
+       cache->flag = 0;
 
        sculpt_init_mirror_clipping(ob, ss);
 
        /* Initial mouse location */
        if (mouse)
-               copy_v2_v2(ss->cache->initial_mouse, mouse);
+               copy_v2_v2(cache->initial_mouse, mouse);
        else
-               zero_v2(ss->cache->initial_mouse);
+               zero_v2(cache->initial_mouse);
 
        mode = RNA_enum_get(op->ptr, "mode");
        cache->invert = mode == BRUSH_STROKE_INVERT;
@@ -3742,7 +3692,7 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
        else brush->flag &= ~BRUSH_INVERTED;
 
        /* Alt-Smooth */
-       if (ss->cache->alt_smooth) {
+       if (cache->alt_smooth) {
                if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
                        cache->saved_mask_brush_tool = brush->mask_tool;
                        brush->mask_tool = BRUSH_MASK_SMOOTH;
@@ -3763,7 +3713,7 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
        }
 
        copy_v2_v2(cache->mouse, cache->initial_mouse);
-       copy_v2_v2(cache->tex_mouse, cache->initial_mouse);
+       copy_v2_v2(ups->tex_mouse, cache->initial_mouse);
 
        /* Truly temporary data that isn't stored in properties */
 
@@ -3818,8 +3768,6 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
                }
        }
 
-       cache->special_rotation = (brush->flag & BRUSH_RAKE) ? ups->last_angle : 0;
-
        cache->first_time = 1;
 
        cache->vertex_rotation = 0;
@@ -3890,9 +3838,9 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
                copy_v3_v3(cache->old_grab_location, grab_location);
 
                if (tool == SCULPT_TOOL_GRAB)
-                       copy_v3_v3(ups->anchored_location, cache->true_location);
+                       copy_v3_v3(cache->anchored_location, cache->true_location);
                else if (tool == SCULPT_TOOL_THUMB)
-                       copy_v3_v3(ups->anchored_location, cache->orig_grab_location);
+                       copy_v3_v3(cache->anchored_location, cache->orig_grab_location);
 
                if (ELEM(tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB)) {
                        /* location stays the same for finding vertices in brush radius */
@@ -3900,7 +3848,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
 
                        ups->draw_anchored = 1;
                        copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse);
-                       ups->anchored_size = cache->pixel_radius;
+                       ups->anchored_size = ups->pixel_radius;
                }
        }
 }
@@ -3935,18 +3883,11 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob,
         *      brush coord/pressure/etc.
         *      It's more an events design issue, which doesn't split coordinate/pressure/angle
         *      changing events. We should avoid this after events system re-design */
-       if (paint_supports_dynamic_size(brush) || cache->first_time) {
+       if (paint_supports_dynamic_size(brush, PAINT_SCULPT) || cache->first_time) {
                cache->pressure = RNA_float_get(ptr, "pressure");
        }
 
        /* Truly temporary data that isn't stored in properties */
-
-       ups->draw_pressure =  1;
-       ups->pressure_value = cache->pressure;
-
-       cache->previous_pixel_radius = cache->pixel_radius;
-       cache->pixel_radius = BKE_brush_size_get(scene, brush);
-
        if (cache->first_time) {
                if (!BKE_brush_use_locked_size(scene, brush)) {
                        cache->initial_radius = paint_calc_object_space_radius(cache->vc,
@@ -3959,8 +3900,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob,
                }
        }
 
-       if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush)) {
-               cache->pixel_radius *= cache->pressure;
+       if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, PAINT_SCULPT)) {
                cache->radius = cache->initial_radius * cache->pressure;
        }
        else {
@@ -3969,77 +3909,25 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob,
 
        cache->radius_squared = cache->radius * cache->radius;
 
-       if (!(brush->flag & BRUSH_ANCHORED ||
-             ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK,
-                   SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE)))
-       {
-               copy_v2_v2(cache->tex_mouse, cache->mouse);
-
-               if ((brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) &&
-                   (brush->flag & BRUSH_RANDOM_ROTATION) &&
-                   !(brush->flag & BRUSH_RAKE))
-               {
-                       cache->special_rotation = 2.0f * (float)M_PI * BLI_frand();
-               }
-       }
-
        if (brush->flag & BRUSH_ANCHORED) {
-               int hit = 0;
-
-               const float dx = cache->mouse[0] - cache->initial_mouse[0];
-               const float dy = cache->mouse[1] - cache->initial_mouse[1];
-
-               ups->anchored_size = cache->pixel_radius = sqrt(dx * dx + dy * dy);
-
-               cache->special_rotation = atan2(dx, dy) + M_PI;
-
                if (brush->flag & BRUSH_EDGE_TO_EDGE) {
                        float halfway[2];
                        float out[3];
-
-                       halfway[0] = dx * 0.5f + cache->initial_mouse[0];
-                       halfway[1] = dy * 0.5f + cache->initial_mouse[1];
+                       halfway[0] = 0.5f * (cache->mouse[0] + cache->initial_mouse[0]);
+                       halfway[1] = 0.5f * (cache->mouse[1] + cache->initial_mouse[1]);
 
                        if (sculpt_stroke_get_location(C, out, halfway)) {
-                               copy_v3_v3(ups->anchored_location, out);
-                               copy_v2_v2(ups->anchored_initial_mouse, halfway);
-                               copy_v2_v2(cache->tex_mouse, halfway);
-                               copy_v3_v3(cache->true_location, ups->anchored_location);
-                               ups->anchored_size /= 2.0f;
-                               cache->pixel_radius  /= 2.0f;
-                               hit = 1;
+                               copy_v3_v3(cache->anchored_location, out);
+                               copy_v3_v3(cache->true_location, cache->anchored_location);
                        }
                }
 
-               if (!hit)
-                       copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse);
-
                cache->radius = paint_calc_object_space_radius(paint_stroke_view_context(stroke),
                                                               cache->true_location,
-                                                              cache->pixel_radius);
+                                                              ups->pixel_radius);
                cache->radius_squared = cache->radius * cache->radius;
 
-               copy_v3_v3(ups->anchored_location, cache->true_location);
-
-               ups->draw_anchored = 1;
-       }
-       else if (brush->flag & BRUSH_RAKE) {
-               const float u = 0.5f;
-               const float v = 1 - u;
-               const float r = 20;
-
-               const float dx = cache->last_rake[0] - cache->mouse[0];
-               const float dy = cache->last_rake[1] - cache->mouse[1];
-
-               if (cache->first_time) {
-                       copy_v2_v2(cache->last_rake, cache->mouse);
-               }
-               else if (dx * dx + dy * dy >= r * r) {
-                       cache->special_rotation = atan2(dx, dy);
-
-                       cache->last_rake[0] = u * cache->last_rake[0] + v * cache->mouse[0];
-                       cache->last_rake[1] = u * cache->last_rake[1] + v * cache->mouse[1];
-               }
+               copy_v3_v3(cache->anchored_location, cache->true_location);
        }
 
        sculpt_update_brush_delta(ups, ob, brush);
@@ -4052,11 +3940,11 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob,
 
                ups->draw_anchored = 1;
                copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse);
-               copy_v3_v3(ups->anchored_location, cache->true_location);
-               ups->anchored_size = cache->pixel_radius;
+               copy_v3_v3(cache->anchored_location, cache->true_location);
+               ups->anchored_size = ups->pixel_radius;
        }
 
-       ups->special_rotation = cache->special_rotation;
+       cache->special_rotation = ups->brush_rotation;
 }
 
 /* Returns true if any of the smoothing modes are active (currently
@@ -4312,6 +4200,7 @@ static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op,
 
 static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
 {
+       UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
        Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
        Object *ob = CTX_data_active_object(C);
        SculptSession *ss = ob->sculpt;
@@ -4323,7 +4212,7 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
 
        BKE_pbvh_bmesh_detail_size_set(ss->pbvh,
                                       (ss->cache->radius /
-                                       (float)ss->cache->pixel_radius) *
+                                       (float)ups->pixel_radius) *
                                       (float)sd->detail_size);
 
        if (sculpt_stroke_dynamic_topology(ss, brush)) {
@@ -4368,7 +4257,6 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
        /* reset values used to draw brush after completing the stroke */
        ups->draw_anchored = 0;
        ups->draw_pressure = 0;
-       ups->special_rotation = 0;
 
        /* Finished */
        if (ss->cache) {
index fa6fd41f568a64c1eeff526061a53aa05e82a347..cd1acb5302964c1eb5f1a7ed65e4680a37a1b7fb 100644 (file)
@@ -888,20 +888,25 @@ typedef struct UnifiedPaintSettings {
        /* rake rotation */
 
        /* record movement of mouse so that rake can start at an intuitive angle */
-       float last_x, last_y;
-       float last_angle;
+       float last_rake[2];
+       int pad;
 
-       float special_rotation;
+       float brush_rotation;
 
        // all this below is used to communicate with the cursor drawing routine
        int draw_anchored;
        int   anchored_size;
-       float anchored_location[3];
        float anchored_initial_mouse[2];
 
        /* drawing pressure */
        int draw_pressure;
        float pressure_value;
+
+       /* position of mouse, used to sample the texture */
+       float tex_mouse[2];
+       /* radius of brush, premultiplied with pressure.
+        * In case of anchored brushes contains that radius */
+       float pixel_radius;
 } UnifiedPaintSettings;
 
 typedef enum {