Fix #35337: sculpt performance regression, partial redraw was not working anymore
[blender.git] / source / blender / editors / sculpt_paint / paint_stroke.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software  Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2009 by Nicholas Bishop
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Jason Wilkins, Tom Musgrove.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  *
27  */
28
29 /** \file blender/editors/sculpt_paint/paint_stroke.c
30  *  \ingroup edsculpt
31  */
32
33
34 #include "MEM_guardedalloc.h"
35
36 #include "BLI_math.h"
37 #include "BLI_utildefines.h"
38 #include "BLI_rand.h"
39
40 #include "DNA_object_types.h"
41 #include "DNA_scene_types.h"
42 #include "DNA_brush_types.h"
43
44 #include "RNA_access.h"
45
46 #include "BKE_context.h"
47 #include "BKE_paint.h"
48 #include "BKE_brush.h"
49
50 #include "WM_api.h"
51 #include "WM_types.h"
52
53 #include "BIF_gl.h"
54 #include "BIF_glutil.h"
55
56 #include "ED_screen.h"
57 #include "ED_view3d.h"
58
59 #include "paint_intern.h"
60
61 #include <float.h>
62 #include <math.h>
63
64 typedef struct PaintSample {
65         float mouse[2];
66
67         /* TODO: other input properties, e.g. tablet pressure */
68 } PaintSample;
69
70 typedef struct PaintStroke {
71         void *mode_data;
72         void *smooth_stroke_cursor;
73         wmTimer *timer;
74
75         /* Cached values */
76         ViewContext vc;
77         bglMats mats;
78         Brush *brush;
79
80         /* Paint stroke can use up to PAINT_MAX_INPUT_SAMPLES prior inputs
81          * to smooth the stroke */
82         PaintSample samples[PAINT_MAX_INPUT_SAMPLES];
83         int num_samples;
84         int cur_sample;
85
86         float last_mouse_position[2];
87
88         /* Set whether any stroke step has yet occurred
89          * e.g. in sculpt mode, stroke doesn't start until cursor
90          * passes over the mesh */
91         int stroke_started;
92         /* event that started stroke, for modal() return */
93         int event_type;
94         
95         bool brush_init;
96         float initial_mouse[2];
97         float cached_pressure;
98
99         float zoom_2d;
100
101         StrokeGetLocation get_location;
102         StrokeTestStart test_start;
103         StrokeUpdateStep update_step;
104         StrokeDone done;
105 } PaintStroke;
106
107 /*** Cursor ***/
108 static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata) 
109 {
110         Paint *paint = BKE_paint_get_active_from_context(C);
111         Brush *brush = BKE_paint_brush(paint);
112         PaintStroke *stroke = customdata;
113
114         if (stroke && brush && (brush->flag & BRUSH_SMOOTH_STROKE)) {
115                 glColor4ubv(paint->paint_cursor_col);
116                 glEnable(GL_LINE_SMOOTH);
117                 glEnable(GL_BLEND);
118
119                 sdrawline(x, y, (int)stroke->last_mouse_position[0],
120                           (int)stroke->last_mouse_position[1]);
121                 glDisable(GL_BLEND);
122                 glDisable(GL_LINE_SMOOTH);
123         }
124 }
125
126 /* if this is a tablet event, return tablet pressure and set *pen_flip
127  * to 1 if the eraser tool is being used, 0 otherwise */
128 static float event_tablet_data(const wmEvent *event, int *pen_flip)
129 {
130         int erasor = 0;
131         float pressure = 1;
132
133         if (event->tablet_data) {
134                 wmTabletData *wmtab = event->tablet_data;
135
136                 erasor = (wmtab->Active == EVT_TABLET_ERASER);
137                 pressure = (wmtab->Active != EVT_TABLET_NONE) ? wmtab->Pressure : 1;
138         }
139
140         if (pen_flip)
141                 (*pen_flip) = erasor;
142
143         return pressure;
144 }
145
146
147 /* Initialize the stroke cache variants from operator properties */
148 static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode,
149                                          struct PaintStroke *stroke,
150                                          const float mouse[2], float pressure)
151 {
152         Scene *scene = CTX_data_scene(C);
153         UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
154
155         /* XXX: Use pressure value from first brush step for brushes which don't
156          *      support strokes (grab, thumb). They depends on initial state and
157          *      brush coord/pressure/etc.
158          *      It's more an events design issue, which doesn't split coordinate/pressure/angle
159          *      changing events. We should avoid this after events system re-design */
160         if (paint_supports_dynamic_size(brush, mode) || !stroke->brush_init) {
161                 copy_v2_v2(stroke->initial_mouse, mouse);
162                 copy_v2_v2(ups->tex_mouse, mouse);
163                 copy_v2_v2(ups->mask_tex_mouse, mouse);
164                 stroke->cached_pressure = pressure;
165         }
166
167         /* Truly temporary data that isn't stored in properties */
168
169         ups->draw_pressure = TRUE;
170         ups->pressure_value = stroke->cached_pressure;
171
172         ups->pixel_radius = BKE_brush_size_get(scene, brush);
173
174         if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, mode)) {
175                 ups->pixel_radius *= stroke->cached_pressure;
176         }
177
178         if (paint_supports_dynamic_tex_coords(brush, mode)) {
179                 if (((brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) ||
180                     (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)) &&
181                     !(brush->flag & BRUSH_RAKE))
182                 {
183                         if (brush->flag & BRUSH_RANDOM_ROTATION)
184                                 ups->brush_rotation = 2.0f * (float)M_PI * BLI_frand();
185                         else
186                                 ups->brush_rotation = 0.0f;
187                 }
188
189                 if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
190                         BKE_brush_randomize_texture_coordinates(ups, false);
191                 else {
192                         copy_v2_v2(ups->tex_mouse, mouse);
193                 }
194         }
195
196         /* take care of mask texture, if any */
197         if (brush->mask_mtex.tex) {
198                 if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
199                         BKE_brush_randomize_texture_coordinates(ups, true);
200                 else {
201                         copy_v2_v2(ups->mask_tex_mouse, mouse);
202                 }
203         }
204
205
206         if (brush->flag & BRUSH_ANCHORED) {
207                 bool hit = false;
208                 float halfway[2];
209
210                 const float dx = mouse[0] - stroke->initial_mouse[0];
211                 const float dy = mouse[1] - stroke->initial_mouse[1];
212
213                 ups->anchored_size = ups->pixel_radius = sqrt(dx * dx + dy * dy);
214
215                 ups->brush_rotation = atan2(dx, dy) + M_PI;
216
217                 if (brush->flag & BRUSH_EDGE_TO_EDGE) {
218                         float out[3];
219
220                         halfway[0] = dx * 0.5f + stroke->initial_mouse[0];
221                         halfway[1] = dy * 0.5f + stroke->initial_mouse[1];
222
223                         if (stroke->get_location) {
224                                 if (stroke->get_location(C, out, halfway)) {
225                                         hit = true;
226                                 }
227                         }
228                         else {
229                                 hit = true;
230                         }
231                 }
232                 if (hit) {
233                         copy_v2_v2(ups->anchored_initial_mouse, halfway);
234                         copy_v2_v2(ups->tex_mouse, halfway);
235                         ups->anchored_size /= 2.0f;
236                         ups->pixel_radius  /= 2.0f;
237                 }
238                 else
239                         copy_v2_v2(ups->anchored_initial_mouse, stroke->initial_mouse);
240
241                 ups->draw_anchored = 1;
242         }
243         else if (brush->flag & BRUSH_RAKE) {
244                 if (!stroke->brush_init)
245                         copy_v2_v2(ups->last_rake, mouse);
246                 else
247                         paint_calculate_rake_rotation(ups, mouse);
248         }
249
250         stroke->brush_init = TRUE;
251 }
252
253
254 /* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */
255 static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const wmEvent *event, const float mouse_in[2])
256 {
257         Scene *scene = CTX_data_scene(C);
258         wmWindow *window = CTX_wm_window(C);
259         ARegion *ar = CTX_wm_region(C);
260         Paint *paint = BKE_paint_get_active_from_context(C);
261         PaintMode mode = BKE_paintmode_get_active_from_context(C);
262         Brush *brush = BKE_paint_brush(paint);
263         PaintStroke *stroke = op->customdata;
264         float mouse_out[2];
265         PointerRNA itemptr;
266         float location[3];
267         float pressure;
268         int pen_flip;
269
270         /* see if tablet affects event */
271         pressure = event_tablet_data(event, &pen_flip);
272
273 /* the following code is adapted from texture paint. It may not be needed but leaving here
274  * just in case for reference (code in texpaint removed as part of refactoring).
275  * It's strange that only texpaint had these guards. */
276 #if 0
277         /* special exception here for too high pressure values on first touch in
278          * windows for some tablets, then we just skip first touch ..  */
279         if (tablet && (pressure >= 0.99f) && ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) || BKE_brush_use_alpha_pressure(scene, pop->s.brush) || BKE_brush_use_size_pressure(scene, pop->s.brush)))
280                 return;
281
282         /* This can be removed once fixed properly in
283          * BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, double time, float pressure, void *user)
284          * at zero pressure we should do nothing 1/2^12 is 0.0002 which is the sensitivity of the most sensitive pen tablet available */
285         if (tablet && (pressure < 0.0002f) && ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) || BKE_brush_use_alpha_pressure(scene, pop->s.brush) || BKE_brush_use_size_pressure(scene, pop->s.brush)))
286                 return;
287 #endif
288
289         /* copy last position -before- jittering, or space fill code
290          * will create too many dabs */
291         copy_v2_v2(stroke->last_mouse_position, mouse_in);
292
293         paint_brush_update(C, brush, mode, stroke, mouse_in, pressure);
294
295         {
296                 float delta[2];
297                 float factor = stroke->zoom_2d;
298
299                 if (brush->flag & BRUSH_JITTER_PRESSURE)
300                         factor *= pressure;
301
302                 BKE_brush_jitter_pos(scene, brush, mouse_in, mouse_out);
303
304                 /* XXX: meh, this is round about because
305                  * BKE_brush_jitter_pos isn't written in the best way to
306                  * be reused here */
307                 if (factor != 1.0f) {
308                         sub_v2_v2v2(delta, mouse_out, mouse_in);
309                         mul_v2_fl(delta, factor);
310                         add_v2_v2v2(mouse_out, mouse_in, delta);
311                 }
312         }
313
314         /* TODO: can remove the if statement once all modes have this */
315         if (stroke->get_location)
316                 stroke->get_location(C, location, mouse_out);
317         else
318                 zero_v3(location);
319
320         /* Add to stroke */
321         RNA_collection_add(op->ptr, "stroke", &itemptr);
322
323         RNA_float_set_array(&itemptr, "location", location);
324         RNA_float_set_array(&itemptr, "mouse", mouse_out);
325         RNA_boolean_set(&itemptr, "pen_flip", pen_flip);
326         RNA_float_set(&itemptr, "pressure", pressure);
327
328         stroke->update_step(C, stroke, &itemptr);
329
330         /* always redraw region if brush is shown */
331         if (ar && (paint->flags & PAINT_SHOW_BRUSH))
332                 WM_paint_cursor_tag_redraw(window, ar);
333 }
334
335 /* Returns zero if no sculpt changes should be made, non-zero otherwise */
336 static int paint_smooth_stroke(PaintStroke *stroke, float output[2],
337                                const PaintSample *sample, PaintMode mode)
338 {
339         output[0] = sample->mouse[0];
340         output[1] = sample->mouse[1];
341
342         if (paint_supports_smooth_stroke(stroke->brush, mode)) {
343                 float radius = stroke->brush->smooth_stroke_radius * stroke->zoom_2d;
344                 float u = stroke->brush->smooth_stroke_factor, v = 1.0f - u;
345                 float dx = stroke->last_mouse_position[0] - sample->mouse[0];
346                 float dy = stroke->last_mouse_position[1] - sample->mouse[1];
347
348                 /* If the mouse is moving within the radius of the last move,
349                  * don't update the mouse position. This allows sharp turns. */
350                 if (dx * dx + dy * dy <  radius * radius)
351                         return 0;
352
353                 output[0] = sample->mouse[0] * v + stroke->last_mouse_position[0] * u;
354                 output[1] = sample->mouse[1] * v + stroke->last_mouse_position[1] * u;
355         }
356
357         return 1;
358 }
359
360 /* For brushes with stroke spacing enabled, moves mouse in steps
361  * towards the final mouse location. */
362 static int paint_space_stroke(bContext *C, wmOperator *op, const wmEvent *event, const float final_mouse[2])
363 {
364         PaintStroke *stroke = op->customdata;
365         PaintMode mode = BKE_paintmode_get_active_from_context(C);
366
367         int cnt = 0;
368
369         if (paint_space_stroke_enabled(stroke->brush, mode)) {
370                 float mouse[2];
371                 float vec[2];
372                 float length, scale;
373
374                 copy_v2_v2(mouse, stroke->last_mouse_position);
375                 sub_v2_v2v2(vec, final_mouse, mouse);
376
377                 length = len_v2(vec);
378
379                 if (length > FLT_EPSILON) {
380                         const Scene *scene = CTX_data_scene(C);
381                         int steps;
382                         int i;
383                         float size_pressure = 1.0f;
384                         float pressure = event_tablet_data(event, NULL);
385
386                         /* XXX mysterious :) what has 'use size' do with this here... if you don't check for it, pressure fails */
387                         if (BKE_brush_use_size_pressure(scene, stroke->brush))
388                                 size_pressure = pressure;
389                         
390                         if (size_pressure > FLT_EPSILON) {
391                                 /* brushes can have a minimum size of 1.0 but with pressure it can be smaller then a pixel
392                                  * causing very high step sizes, hanging blender [#32381] */
393                                 const float size_clamp = max_ff(1.0f, BKE_brush_size_get(scene, stroke->brush) * size_pressure);
394                                 float spacing = stroke->brush->spacing;
395
396                                 /* stroke system is used for 2d paint too, so we need to account for
397                                  * the fact that brush can be scaled there. */
398
399                                 if (stroke->brush->flag & BRUSH_SPACING_PRESSURE)
400                                         spacing = max_ff(1.0f, spacing * (1.5f - pressure));
401
402                                 spacing *= stroke->zoom_2d;
403
404                                 scale = (size_clamp * spacing / 50.0f) / length;
405                                 if (scale > FLT_EPSILON) {
406                                         mul_v2_fl(vec, scale);
407
408                                         steps = (int)(1.0f / scale);
409
410                                         for (i = 0; i < steps; ++i, ++cnt) {
411                                                 add_v2_v2(mouse, vec);
412                                                 paint_brush_stroke_add_step(C, op, event, mouse);
413                                         }
414                                 }
415                         }
416                 }
417         }
418
419         return cnt;
420 }
421
422 /**** Public API ****/
423
424 PaintStroke *paint_stroke_new(bContext *C,
425                               StrokeGetLocation get_location,
426                               StrokeTestStart test_start,
427                               StrokeUpdateStep update_step,
428                               StrokeDone done, int event_type)
429 {
430         PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke");
431
432         Brush *br = stroke->brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
433         view3d_set_viewcontext(C, &stroke->vc);
434         if (stroke->vc.v3d)
435                 view3d_get_transformation(stroke->vc.ar, stroke->vc.rv3d, stroke->vc.obact, &stroke->mats);
436
437         stroke->get_location = get_location;
438         stroke->test_start = test_start;
439         stroke->update_step = update_step;
440         stroke->done = done;
441         stroke->event_type = event_type; /* for modal, return event */
442         
443         BKE_paint_set_overlay_override(br->overlay_flags);
444
445         return stroke;
446 }
447
448 void paint_stroke_data_free(struct wmOperator *op)
449 {
450         BKE_paint_set_overlay_override(0);
451         MEM_freeN(op->customdata);
452         op->customdata = NULL;
453 }
454
455 static void stroke_done(struct bContext *C, struct wmOperator *op)
456 {
457         struct PaintStroke *stroke = op->customdata;
458
459         if (stroke->stroke_started && stroke->done)
460                 stroke->done(C, stroke);
461
462         if (stroke->timer) {
463                 WM_event_remove_timer(
464                         CTX_wm_manager(C),
465                         CTX_wm_window(C),
466                         stroke->timer);
467         }
468
469         if (stroke->smooth_stroke_cursor)
470                 WM_paint_cursor_end(CTX_wm_manager(C), stroke->smooth_stroke_cursor);
471
472         paint_stroke_data_free(op);
473 }
474
475 /* Returns zero if the stroke dots should not be spaced, non-zero otherwise */
476 bool paint_space_stroke_enabled(Brush *br, PaintMode mode)
477 {
478         return (br->flag & BRUSH_SPACE) && paint_supports_dynamic_size(br, mode);
479 }
480
481 static bool sculpt_is_grab_tool(Brush *br)
482 {
483         return ELEM4(br->sculpt_tool,
484                      SCULPT_TOOL_GRAB,
485                      SCULPT_TOOL_THUMB,
486                      SCULPT_TOOL_ROTATE,
487                      SCULPT_TOOL_SNAKE_HOOK);
488 }
489
490 /* return true if the brush size can change during paint (normally used for pressure) */
491 bool paint_supports_dynamic_size(Brush *br, PaintMode mode)
492 {
493         if (br->flag & BRUSH_ANCHORED)
494                 return false;
495
496         switch (mode) {
497                 case PAINT_SCULPT:
498                         if (sculpt_is_grab_tool(br))
499                                 return false;
500                 default:
501                         ;
502         }
503         return true;
504 }
505
506 bool paint_supports_smooth_stroke(Brush *br, PaintMode mode)
507 {
508         if (!(br->flag & BRUSH_SMOOTH_STROKE) ||
509              (br->flag & BRUSH_ANCHORED) ||
510              (br->flag & BRUSH_RESTORE_MESH))
511         {
512                 return false;
513         }
514
515         switch (mode) {
516                 case PAINT_SCULPT:
517                         if (sculpt_is_grab_tool(br))
518                                 return false;
519                 default:
520                         ;
521         }
522         return true;
523 }
524
525 /* return true if the brush size can change during paint (normally used for pressure) */
526 bool paint_supports_dynamic_tex_coords(Brush *br, PaintMode mode)
527 {
528         if (br->flag & BRUSH_ANCHORED)
529                 return false;
530
531         switch (mode) {
532                 case PAINT_SCULPT:
533                         if (sculpt_is_grab_tool(br))
534                                 return false;
535                 default:
536                         ;
537                 }
538         return true;
539 }
540
541 #define PAINT_STROKE_MODAL_CANCEL 1
542
543 /* called in paint_ops.c, on each regeneration of keymaps  */
544 struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf)
545 {
546         static struct EnumPropertyItem modal_items[] = {
547                 {PAINT_STROKE_MODAL_CANCEL, "CANCEL", 0,
548                 "Cancel",
549                 "Cancel and undo a stroke in progress"},
550
551                 { 0 }
552         };
553
554         static const char *name = "Paint Stroke Modal";
555
556         struct wmKeyMap *keymap = WM_modalkeymap_get(keyconf, name);
557
558         /* this function is called for each spacetype, only needs to add map once */
559         if (!keymap) {
560                 keymap = WM_modalkeymap_add(keyconf, name, modal_items);
561
562                 /* items for modal map */
563                 WM_modalkeymap_add_item(
564                         keymap, ESCKEY, KM_PRESS, KM_ANY, 0, PAINT_STROKE_MODAL_CANCEL);
565         }
566
567         return keymap;
568 }
569
570 static void paint_stroke_add_sample(const Paint *paint,
571                                     PaintStroke *stroke,
572                                     float x, float y)
573 {
574         PaintSample *sample = &stroke->samples[stroke->cur_sample];
575         int max_samples = MIN2(PAINT_MAX_INPUT_SAMPLES,
576                                MAX2(paint->num_input_samples, 1));
577
578         sample->mouse[0] = x;
579         sample->mouse[1] = y;
580
581         stroke->cur_sample++;
582         if (stroke->cur_sample >= max_samples)
583                 stroke->cur_sample = 0;
584         if (stroke->num_samples < max_samples)
585                 stroke->num_samples++;
586 }
587
588 static void paint_stroke_sample_average(const PaintStroke *stroke,
589                                         PaintSample *average)
590 {
591         int i;
592         
593         memset(average, 0, sizeof(*average));
594
595         BLI_assert(stroke->num_samples > 0);
596         
597         for (i = 0; i < stroke->num_samples; i++)
598                 add_v2_v2(average->mouse, stroke->samples[i].mouse);
599
600         mul_v2_fl(average->mouse, 1.0f / stroke->num_samples);
601
602         /*printf("avg=(%f, %f), num=%d\n", average->mouse[0], average->mouse[1], stroke->num_samples);*/
603 }
604
605 int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
606 {
607         Paint *p = BKE_paint_get_active_from_context(C);
608         PaintMode mode = BKE_paintmode_get_active_from_context(C);
609         PaintStroke *stroke = op->customdata;
610         PaintSample sample_average;
611         float mouse[2];
612         int first = 0;
613         float zoomx, zoomy;
614
615         paint_stroke_add_sample(p, stroke, event->mval[0], event->mval[1]);
616         paint_stroke_sample_average(stroke, &sample_average);
617
618         get_imapaint_zoom(C, &zoomx, &zoomy);
619         stroke->zoom_2d = max_ff(zoomx, zoomy);
620
621         /* let NDOF motion pass through to the 3D view so we can paint and rotate simultaneously!
622          * this isn't perfect... even when an extra MOUSEMOVE is spoofed, the stroke discards it
623          * since the 2D deltas are zero -- code in this file needs to be updated to use the
624          * post-NDOF_MOTION MOUSEMOVE */
625         if (event->type == NDOF_MOTION)
626                 return OPERATOR_PASS_THROUGH;
627
628         if (!stroke->stroke_started) {
629                 copy_v2_v2(stroke->last_mouse_position, sample_average.mouse);
630                 stroke->stroke_started = stroke->test_start(C, op, sample_average.mouse);
631                 BLI_assert((stroke->stroke_started & ~1) == 0);  /* 0/1 */
632
633                 if (stroke->stroke_started) {
634                         stroke->smooth_stroke_cursor =
635                             WM_paint_cursor_activate(CTX_wm_manager(C), paint_poll, paint_draw_smooth_stroke, stroke);
636
637                         if (stroke->brush->flag & BRUSH_AIRBRUSH)
638                                 stroke->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, stroke->brush->rate);
639                 }
640
641                 first = 1;
642                 //ED_region_tag_redraw(ar);
643         }
644
645         /* Cancel */
646         if (event->type == EVT_MODAL_MAP && event->val == PAINT_STROKE_MODAL_CANCEL) {
647                 if (op->type->cancel)
648                         return op->type->cancel(C, op);
649                 else
650                         return paint_stroke_cancel(C, op);
651         }
652
653         if (event->type == stroke->event_type && event->val == KM_RELEASE) {
654                 stroke_done(C, op);
655                 return OPERATOR_FINISHED;
656         }
657         else if ((first) ||
658                  (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) ||
659                  (event->type == TIMER && (event->customdata == stroke->timer)) )
660         {
661                 if (stroke->stroke_started) {
662                         if (paint_smooth_stroke(stroke, mouse, &sample_average, mode)) {
663                                 if (paint_space_stroke_enabled(stroke->brush, mode)) {
664                                         if (!paint_space_stroke(C, op, event, mouse)) {
665                                                 //ED_region_tag_redraw(ar);
666                                         }
667                                 }
668                                 else {
669                                         paint_brush_stroke_add_step(C, op, event, mouse);
670                                 }
671                         }
672                         else {
673                                 ; //ED_region_tag_redraw(ar);
674                         }
675                 }
676         }
677
678         /* we want the stroke to have the first daub at the start location
679          * instead of waiting till we have moved the space distance */
680         if (first &&
681             stroke->stroke_started &&
682             paint_space_stroke_enabled(stroke->brush, mode) &&
683             !(stroke->brush->flag & BRUSH_ANCHORED) &&
684             !(stroke->brush->flag & BRUSH_SMOOTH_STROKE))
685         {
686                 paint_brush_stroke_add_step(C, op, event, mouse);
687         }
688         
689         return OPERATOR_RUNNING_MODAL;
690 }
691
692 int paint_stroke_exec(bContext *C, wmOperator *op)
693 {
694         PaintStroke *stroke = op->customdata;
695
696         /* only when executed for the first time */
697         if (stroke->stroke_started == 0) {
698                 /* XXX stroke->last_mouse_position is unset, this may cause problems */
699                 stroke->test_start(C, op, NULL);
700                 stroke->stroke_started = 1;
701         }
702
703         RNA_BEGIN (op->ptr, itemptr, "stroke")
704         {
705                 stroke->update_step(C, stroke, &itemptr);
706         }
707         RNA_END;
708
709         stroke_done(C, op);
710
711         return OPERATOR_FINISHED;
712 }
713
714 int paint_stroke_cancel(bContext *C, wmOperator *op)
715 {
716         stroke_done(C, op);
717         return OPERATOR_CANCELLED;
718 }
719
720 ViewContext *paint_stroke_view_context(PaintStroke *stroke)
721 {
722         return &stroke->vc;
723 }
724
725 void *paint_stroke_mode_data(struct PaintStroke *stroke)
726 {
727         return stroke->mode_data;
728 }
729
730 void paint_stroke_set_mode_data(PaintStroke *stroke, void *mode_data)
731 {
732         stroke->mode_data = mode_data;
733 }
734
735 int paint_poll(bContext *C)
736 {
737         Paint *p = BKE_paint_get_active_from_context(C);
738         Object *ob = CTX_data_active_object(C);
739         ScrArea *sa = CTX_wm_area(C);
740         ARegion *ar = CTX_wm_region(C);
741
742         return p && ob && BKE_paint_brush(p) &&
743                (sa && sa->spacetype == SPACE_VIEW3D) &&
744                (ar && ar->regiontype == RGN_TYPE_WINDOW);
745 }