code cleanup:
[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 = paint_get_active_from_context(C);
111         Brush *brush = 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                 stroke->cached_pressure = pressure;
164         }
165
166         /* Truly temporary data that isn't stored in properties */
167
168         ups->draw_pressure = TRUE;
169         ups->pressure_value = stroke->cached_pressure;
170
171         ups->pixel_radius = BKE_brush_size_get(scene, brush);
172
173         if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, mode)) {
174                 ups->pixel_radius *= stroke->cached_pressure;
175         }
176
177         if (!(brush->flag & BRUSH_ANCHORED ||
178               ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK,
179                     SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE)))
180         {
181                 if (((brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) ||
182                     (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)) &&
183                     !(brush->flag & BRUSH_RAKE))
184                 {
185                         if (brush->flag & BRUSH_RANDOM_ROTATION)
186                                 ups->brush_rotation = 2.0f * (float)M_PI * BLI_frand();
187                         else
188                                 ups->brush_rotation = 0.0f;
189                 }
190
191                 if ((brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)) {
192                         ups->tex_mouse[0] = BLI_frand() * stroke->vc.ar->sizex;
193                         ups->tex_mouse[1] = BLI_frand() * stroke->vc.ar->sizey;;
194                 }
195                 else {
196                         copy_v2_v2(ups->tex_mouse, mouse);
197                 }
198         }
199
200         if (brush->flag & BRUSH_ANCHORED) {
201                 bool hit = false;
202                 float halfway[2];
203
204                 const float dx = mouse[0] - stroke->initial_mouse[0];
205                 const float dy = mouse[1] - stroke->initial_mouse[1];
206
207                 ups->anchored_size = ups->pixel_radius = sqrt(dx * dx + dy * dy);
208
209                 ups->brush_rotation = atan2(dx, dy) + M_PI;
210
211                 if (brush->flag & BRUSH_EDGE_TO_EDGE) {
212                         float out[3];
213
214                         halfway[0] = dx * 0.5f + stroke->initial_mouse[0];
215                         halfway[1] = dy * 0.5f + stroke->initial_mouse[1];
216
217                         if (stroke->get_location) {
218                                 if (stroke->get_location(C, out, halfway)) {
219                                         hit = true;
220                                 }
221                         }
222                         else {
223                                 hit = true;
224                         }
225                 }
226                 if (hit) {
227                         copy_v2_v2(ups->anchored_initial_mouse, halfway);
228                         copy_v2_v2(ups->tex_mouse, halfway);
229                         ups->anchored_size /= 2.0f;
230                         ups->pixel_radius  /= 2.0f;
231                 }
232                 else
233                         copy_v2_v2(ups->anchored_initial_mouse, stroke->initial_mouse);
234
235                 ups->draw_anchored = 1;
236         }
237         else if (brush->flag & BRUSH_RAKE) {
238                 if (!stroke->brush_init)
239                         copy_v2_v2(ups->last_rake, mouse);
240                 else
241                         paint_calculate_rake_rotation(ups, mouse);
242         }
243
244         stroke->brush_init = TRUE;
245 }
246
247
248 /* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */
249 static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const wmEvent *event, const float mouse_in[2])
250 {
251         Scene *scene = CTX_data_scene(C);
252         Paint *paint = paint_get_active_from_context(C);
253         PaintMode mode = paintmode_get_active_from_context(C);
254         Brush *brush = paint_brush(paint);
255         PaintStroke *stroke = op->customdata;
256         float mouse_out[2];
257         PointerRNA itemptr;
258         float location[3];
259         float pressure;
260         int pen_flip;
261
262         /* see if tablet affects event */
263         pressure = event_tablet_data(event, &pen_flip);
264
265 /* the following code is adapted from texture paint. It may not be needed but leaving here
266  * just in case for reference (code in texpaint removed as part of refactoring).
267  * It's strange that only texpaint had these guards. */
268 #if 0
269         /* special exception here for too high pressure values on first touch in
270          * windows for some tablets, then we just skip first touch ..  */
271         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)))
272                 return;
273
274         /* This can be removed once fixed properly in
275          * BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, double time, float pressure, void *user)
276          * at zero pressure we should do nothing 1/2^12 is 0.0002 which is the sensitivity of the most sensitive pen tablet available */
277         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)))
278                 return;
279 #endif
280
281         /* copy last position -before- jittering, or space fill code
282          * will create too many dabs */
283         copy_v2_v2(stroke->last_mouse_position, mouse_in);
284
285         paint_brush_update(C, brush, mode, stroke, mouse_in, pressure);
286
287         /* TODO: as sculpt and other paint modes are unified, this
288          * separation will go away */
289         if (paint_supports_jitter(mode)) {
290                 float delta[2];
291                 float factor = stroke->zoom_2d;
292
293                 if (brush->flag & BRUSH_JITTER_PRESSURE)
294                         factor *= pressure;
295
296                 BKE_brush_jitter_pos(scene, brush, mouse_in, mouse_out);
297
298                 /* XXX: meh, this is round about because
299                  * BKE_brush_jitter_pos isn't written in the best way to
300                  * be reused here */
301                 if (factor != 1.0f) {
302                         sub_v2_v2v2(delta, mouse_out, mouse_in);
303                         mul_v2_fl(delta, factor);
304                         add_v2_v2v2(mouse_out, mouse_in, delta);
305                 }
306         }
307         else {
308                 copy_v2_v2(mouse_out, mouse_in);
309         }
310
311         /* TODO: can remove the if statement once all modes have this */
312         if (stroke->get_location)
313                 stroke->get_location(C, location, mouse_out);
314         else
315                 zero_v3(location);
316
317         /* Add to stroke */
318         RNA_collection_add(op->ptr, "stroke", &itemptr);
319
320         RNA_float_set_array(&itemptr, "location", location);
321         RNA_float_set_array(&itemptr, "mouse", mouse_out);
322         RNA_boolean_set(&itemptr, "pen_flip", pen_flip);
323         RNA_float_set(&itemptr, "pressure", pressure);
324
325         stroke->update_step(C, stroke, &itemptr);
326 }
327
328 /* Returns zero if no sculpt changes should be made, non-zero otherwise */
329 static int paint_smooth_stroke(PaintStroke *stroke, float output[2],
330                                const PaintSample *sample, PaintMode mode)
331 {
332         output[0] = sample->mouse[0];
333         output[1] = sample->mouse[1];
334
335         if (paint_supports_smooth_stroke(stroke->brush, mode)) {
336                 float radius = stroke->brush->smooth_stroke_radius * stroke->zoom_2d;
337                 float u = stroke->brush->smooth_stroke_factor, v = 1.0f - u;
338                 float dx = stroke->last_mouse_position[0] - sample->mouse[0];
339                 float dy = stroke->last_mouse_position[1] - sample->mouse[1];
340
341                 /* If the mouse is moving within the radius of the last move,
342                  * don't update the mouse position. This allows sharp turns. */
343                 if (dx * dx + dy * dy <  radius * radius)
344                         return 0;
345
346                 output[0] = sample->mouse[0] * v + stroke->last_mouse_position[0] * u;
347                 output[1] = sample->mouse[1] * v + stroke->last_mouse_position[1] * u;
348         }
349
350         return 1;
351 }
352
353 /* For brushes with stroke spacing enabled, moves mouse in steps
354  * towards the final mouse location. */
355 static int paint_space_stroke(bContext *C, wmOperator *op, const wmEvent *event, const float final_mouse[2])
356 {
357         PaintStroke *stroke = op->customdata;
358         PaintMode mode = paintmode_get_active_from_context(C);
359
360         int cnt = 0;
361
362         if (paint_space_stroke_enabled(stroke->brush, mode)) {
363                 float mouse[2];
364                 float vec[2];
365                 float length, scale;
366
367                 copy_v2_v2(mouse, stroke->last_mouse_position);
368                 sub_v2_v2v2(vec, final_mouse, mouse);
369
370                 length = len_v2(vec);
371
372                 if (length > FLT_EPSILON) {
373                         const Scene *scene = CTX_data_scene(C);
374                         int steps;
375                         int i;
376                         float size_pressure = 1.0f;
377                         float pressure = event_tablet_data(event, NULL);
378
379                         /* XXX mysterious :) what has 'use size' do with this here... if you don't check for it, pressure fails */
380                         if (BKE_brush_use_size_pressure(scene, stroke->brush))
381                                 size_pressure = pressure;
382                         
383                         if (size_pressure > FLT_EPSILON) {
384                                 /* brushes can have a minimum size of 1.0 but with pressure it can be smaller then a pixel
385                                  * causing very high step sizes, hanging blender [#32381] */
386                                 const float size_clamp = max_ff(1.0f, BKE_brush_size_get(scene, stroke->brush) * size_pressure);
387                                 float spacing = stroke->brush->spacing;
388
389                                 /* stroke system is used for 2d paint too, so we need to account for
390                                  * the fact that brush can be scaled there. */
391
392                                 if (stroke->brush->flag & BRUSH_SPACING_PRESSURE)
393                                         spacing = max_ff(1.0f, spacing * (1.5f - pressure));
394
395                                 spacing *= stroke->zoom_2d;
396
397                                 scale = (size_clamp * spacing / 50.0f) / length;
398                                 if (scale > FLT_EPSILON) {
399                                         mul_v2_fl(vec, scale);
400
401                                         steps = (int)(1.0f / scale);
402
403                                         for (i = 0; i < steps; ++i, ++cnt) {
404                                                 add_v2_v2(mouse, vec);
405                                                 paint_brush_stroke_add_step(C, op, event, mouse);
406                                         }
407                                 }
408                         }
409                 }
410         }
411
412         return cnt;
413 }
414
415 /**** Public API ****/
416
417 PaintStroke *paint_stroke_new(bContext *C,
418                               StrokeGetLocation get_location,
419                               StrokeTestStart test_start,
420                               StrokeUpdateStep update_step,
421                               StrokeDone done, int event_type)
422 {
423         PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke");
424
425         stroke->brush = paint_brush(paint_get_active_from_context(C));
426         view3d_set_viewcontext(C, &stroke->vc);
427         if (stroke->vc.v3d)
428                 view3d_get_transformation(stroke->vc.ar, stroke->vc.rv3d, stroke->vc.obact, &stroke->mats);
429
430         stroke->get_location = get_location;
431         stroke->test_start = test_start;
432         stroke->update_step = update_step;
433         stroke->done = done;
434         stroke->event_type = event_type; /* for modal, return event */
435         
436         return stroke;
437 }
438
439 void paint_stroke_data_free(struct wmOperator *op)
440 {
441         MEM_freeN(op->customdata);
442         op->customdata = NULL;
443 }
444
445 static void stroke_done(struct bContext *C, struct wmOperator *op)
446 {
447         struct PaintStroke *stroke = op->customdata;
448
449         if (stroke->stroke_started && stroke->done)
450                 stroke->done(C, stroke);
451
452         if (stroke->timer) {
453                 WM_event_remove_timer(
454                         CTX_wm_manager(C),
455                         CTX_wm_window(C),
456                         stroke->timer);
457         }
458
459         if (stroke->smooth_stroke_cursor)
460                 WM_paint_cursor_end(CTX_wm_manager(C), stroke->smooth_stroke_cursor);
461
462         paint_stroke_data_free(op);
463 }
464
465 /* Returns zero if the stroke dots should not be spaced, non-zero otherwise */
466 bool paint_space_stroke_enabled(Brush *br, PaintMode mode)
467 {
468         return (br->flag & BRUSH_SPACE) && paint_supports_dynamic_size(br, mode);
469 }
470
471 /* return true if the brush size can change during paint (normally used for pressure) */
472 bool paint_supports_dynamic_size(Brush *br, PaintMode mode)
473 {
474         if (br->flag & BRUSH_ANCHORED)
475                 return false;
476
477         switch (mode) {
478                 case PAINT_SCULPT:
479                         if (ELEM4(br->sculpt_tool,
480                                   SCULPT_TOOL_GRAB,
481                                   SCULPT_TOOL_THUMB,
482                                   SCULPT_TOOL_ROTATE,
483                                   SCULPT_TOOL_SNAKE_HOOK))
484                         {
485                                 return false;
486                         }
487                 default:
488                         ;
489         }
490         return true;
491 }
492
493 bool paint_supports_smooth_stroke(Brush *br, PaintMode mode)
494 {
495         if (!(br->flag & BRUSH_SMOOTH_STROKE) ||
496              (br->flag & BRUSH_ANCHORED) ||
497              (br->flag & BRUSH_RESTORE_MESH))
498         {
499                 return false;
500         }
501
502         switch (mode) {
503                 case PAINT_SCULPT:
504                         if (ELEM4(br->sculpt_tool,
505                                   SCULPT_TOOL_GRAB,
506                                   SCULPT_TOOL_THUMB,
507                                   SCULPT_TOOL_ROTATE,
508                                   SCULPT_TOOL_SNAKE_HOOK))
509                         {
510                                 return false;
511                         }
512                 default:
513                         ;
514         }
515         return true;
516 }
517
518 /* return true if the brush size can change during paint (normally used for pressure) */
519 bool paint_supports_dynamic_tex_coords(Brush *br, PaintMode mode)
520 {
521         if (br->flag & BRUSH_ANCHORED)
522                 return false;
523
524         switch (mode) {
525                 case PAINT_SCULPT:
526                         if (ELEM4(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK))
527                                 return false;
528                 default:
529                         ;
530                 }
531         return true;
532 }
533
534 bool paint_supports_jitter(PaintMode mode)
535 {
536         return ELEM3(mode, PAINT_SCULPT, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D);
537 }
538
539 #define PAINT_STROKE_MODAL_CANCEL 1
540
541 /* called in paint_ops.c, on each regeneration of keymaps  */
542 struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf)
543 {
544         static struct EnumPropertyItem modal_items[] = {
545                 {PAINT_STROKE_MODAL_CANCEL, "CANCEL", 0,
546                 "Cancel",
547                 "Cancel and undo a stroke in progress"},
548
549                 { 0 }
550         };
551
552         static const char *name = "Paint Stroke Modal";
553
554         struct wmKeyMap *keymap = WM_modalkeymap_get(keyconf, name);
555
556         /* this function is called for each spacetype, only needs to add map once */
557         if (!keymap) {
558                 keymap = WM_modalkeymap_add(keyconf, name, modal_items);
559
560                 /* items for modal map */
561                 WM_modalkeymap_add_item(
562                         keymap, ESCKEY, KM_PRESS, KM_ANY, 0, PAINT_STROKE_MODAL_CANCEL);
563         }
564
565         return keymap;
566 }
567
568 static void paint_stroke_add_sample(const Paint *paint,
569                                     PaintStroke *stroke,
570                                     float x, float y)
571 {
572         PaintSample *sample = &stroke->samples[stroke->cur_sample];
573         int max_samples = MIN2(PAINT_MAX_INPUT_SAMPLES,
574                                MAX2(paint->num_input_samples, 1));
575
576         sample->mouse[0] = x;
577         sample->mouse[1] = y;
578
579         stroke->cur_sample++;
580         if (stroke->cur_sample >= max_samples)
581                 stroke->cur_sample = 0;
582         if (stroke->num_samples < max_samples)
583                 stroke->num_samples++;
584 }
585
586 static void paint_stroke_sample_average(const PaintStroke *stroke,
587                                         PaintSample *average)
588 {
589         int i;
590         
591         memset(average, 0, sizeof(*average));
592
593         BLI_assert(stroke->num_samples > 0);
594         
595         for (i = 0; i < stroke->num_samples; i++)
596                 add_v2_v2(average->mouse, stroke->samples[i].mouse);
597
598         mul_v2_fl(average->mouse, 1.0f / stroke->num_samples);
599
600         /*printf("avg=(%f, %f), num=%d\n", average->mouse[0], average->mouse[1], stroke->num_samples);*/
601 }
602
603 int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
604 {
605         Paint *p = paint_get_active_from_context(C);
606         PaintMode mode = paintmode_get_active_from_context(C);
607         PaintStroke *stroke = op->customdata;
608         PaintSample sample_average;
609         float mouse[2];
610         int first = 0;
611         float zoomx, zoomy;
612
613         paint_stroke_add_sample(p, stroke, event->mval[0], event->mval[1]);
614         paint_stroke_sample_average(stroke, &sample_average);
615
616         get_imapaint_zoom(C, &zoomx, &zoomy);
617         stroke->zoom_2d = max_ff(zoomx, zoomy);
618
619         /* let NDOF motion pass through to the 3D view so we can paint and rotate simultaneously!
620          * this isn't perfect... even when an extra MOUSEMOVE is spoofed, the stroke discards it
621          * since the 2D deltas are zero -- code in this file needs to be updated to use the
622          * post-NDOF_MOTION MOUSEMOVE */
623         if (event->type == NDOF_MOTION)
624                 return OPERATOR_PASS_THROUGH;
625
626         if (!stroke->stroke_started) {
627                 copy_v2_v2(stroke->last_mouse_position, sample_average.mouse);
628                 stroke->stroke_started = stroke->test_start(C, op, sample_average.mouse);
629                 BLI_assert((stroke->stroke_started & ~1) == 0);  /* 0/1 */
630
631                 if (stroke->stroke_started) {
632                         stroke->smooth_stroke_cursor =
633                             WM_paint_cursor_activate(CTX_wm_manager(C), paint_poll, paint_draw_smooth_stroke, stroke);
634
635                         if (stroke->brush->flag & BRUSH_AIRBRUSH)
636                                 stroke->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, stroke->brush->rate);
637                 }
638
639                 first = 1;
640                 //ED_region_tag_redraw(ar);
641         }
642
643         /* Cancel */
644         if (event->type == EVT_MODAL_MAP && event->val == PAINT_STROKE_MODAL_CANCEL) {
645                 if (op->type->cancel)
646                         return op->type->cancel(C, op);
647                 else
648                         return paint_stroke_cancel(C, op);
649         }
650
651         if (event->type == stroke->event_type && event->val == KM_RELEASE) {
652                 stroke_done(C, op);
653                 return OPERATOR_FINISHED;
654         }
655         else if ((first) ||
656                  (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) ||
657                  (event->type == TIMER && (event->customdata == stroke->timer)) )
658         {
659                 if (stroke->stroke_started) {
660                         if (paint_smooth_stroke(stroke, mouse, &sample_average, mode)) {
661                                 if (paint_space_stroke_enabled(stroke->brush, mode)) {
662                                         if (!paint_space_stroke(C, op, event, mouse)) {
663                                                 //ED_region_tag_redraw(ar);
664                                         }
665                                 }
666                                 else {
667                                         paint_brush_stroke_add_step(C, op, event, mouse);
668                                 }
669                         }
670                         else {
671                                 ; //ED_region_tag_redraw(ar);
672                         }
673                 }
674         }
675
676         /* we want the stroke to have the first daub at the start location
677          * instead of waiting till we have moved the space distance */
678         if (first &&
679             stroke->stroke_started &&
680             paint_space_stroke_enabled(stroke->brush, mode) &&
681             !(stroke->brush->flag & BRUSH_ANCHORED) &&
682             !(stroke->brush->flag & BRUSH_SMOOTH_STROKE))
683         {
684                 paint_brush_stroke_add_step(C, op, event, mouse);
685         }
686         
687         return OPERATOR_RUNNING_MODAL;
688 }
689
690 int paint_stroke_exec(bContext *C, wmOperator *op)
691 {
692         PaintStroke *stroke = op->customdata;
693
694         /* only when executed for the first time */
695         if (stroke->stroke_started == 0) {
696                 /* XXX stroke->last_mouse_position is unset, this may cause problems */
697                 stroke->test_start(C, op, NULL);
698                 stroke->stroke_started = 1;
699         }
700
701         RNA_BEGIN (op->ptr, itemptr, "stroke")
702         {
703                 stroke->update_step(C, stroke, &itemptr);
704         }
705         RNA_END;
706
707         stroke_done(C, op);
708
709         return OPERATOR_FINISHED;
710 }
711
712 int paint_stroke_cancel(bContext *C, wmOperator *op)
713 {
714         stroke_done(C, op);
715         return OPERATOR_CANCELLED;
716 }
717
718 ViewContext *paint_stroke_view_context(PaintStroke *stroke)
719 {
720         return &stroke->vc;
721 }
722
723 void *paint_stroke_mode_data(struct PaintStroke *stroke)
724 {
725         return stroke->mode_data;
726 }
727
728 void paint_stroke_set_mode_data(PaintStroke *stroke, void *mode_data)
729 {
730         stroke->mode_data = mode_data;
731 }
732
733 int paint_poll(bContext *C)
734 {
735         Paint *p = paint_get_active_from_context(C);
736         Object *ob = CTX_data_active_object(C);
737         ScrArea *sa = CTX_wm_area(C);
738         ARegion *ar = CTX_wm_region(C);
739
740         return p && ob && paint_brush(p) &&
741                (sa && sa->spacetype == SPACE_VIEW3D) &&
742                (ar && ar->regiontype == RGN_TYPE_WINDOW);
743 }