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