synfig-studio  1.0.3
brush.hpp
Go to the documentation of this file.
1 /* brushlib - The MyPaint Brush Library
2  * Copyright (C) 2007-2011 Martin Renold <martinxyz@gmx.ch>
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <stdio.h>
18 #include <string.h>
19 #include <glib.h>
20 #include <math.h>
21 //#include "Python.h"
22 
23 #include "brushsettings.hpp"
24 #include "mapping.hpp"
25 
26 #define ACTUAL_RADIUS_MIN 0.2
27 #define ACTUAL_RADIUS_MAX 800 // safety guard against radius like 1e20 and against rendering overload with unexpected brush dynamics
28 
29 /* The Brush class stores two things:
30  b) settings: constant during a stroke (eg. size, spacing, dynamics, color selected by the user)
31  a) states: modified during a stroke (eg. speed, smudge colors, time/distance to next dab, position filter states)
32 
33  FIXME: Actually those are two orthogonal things. Should separate them:
34  a) brush settings class that is saved/loaded/selected (without states)
35  b) brush core class to draw the dabs (using an instance of the above)
36 
37  In python, there are two kinds of instances from this: a "global
38  brush" which does the cursor tracking, and the "brushlist" where
39  the states are ignored. When a brush is selected, its settings are
40  copied into the global one, leaving the state intact.
41  */
42 
43 namespace brushlib {
44 
45 class Brush {
46 public:
47  bool print_inputs; // debug menu
48  // for stroke splitting (undo/redo)
51 
52 private:
53  // see also brushsettings.py
54 
55  // the states (get_state, set_state, reset) that change during a stroke
56  float states[STATE_COUNT];
57  GRand * rng;
58 
59  // Those mappings describe how to calculate the current value for each setting.
60  // Most of settings will be constant (eg. only their base_value is used).
61  Mapping * settings[BRUSH_SETTINGS_COUNT];
62 
63  // the current value of all settings (calculated using the current state)
64  float settings_value[BRUSH_SETTINGS_COUNT];
65 
66  // cached calculation results
67  float speed_mapping_gamma[2], speed_mapping_m[2], speed_mapping_q[2];
68 
69  bool reset_requested;
70 
71 public:
72  Brush() {
73  for (int i=0; i<BRUSH_SETTINGS_COUNT; i++) {
74  settings[i] = new Mapping(INPUT_COUNT);
75  }
76  rng = g_rand_new();
77  print_inputs = false;
78 
79  for (int i=0; i<STATE_COUNT; i++) {
80  states[i] = 0;
81  }
82  new_stroke();
83 
84  settings_base_values_have_changed();
85 
86  reset_requested = true;
87  }
88 
89  ~Brush() {
90  for (int i=0; i<BRUSH_SETTINGS_COUNT; i++) {
91  delete settings[i];
92  }
93  g_rand_free (rng); rng = NULL;
94  }
95 
96  void reset()
97  {
98  reset_requested = true;
99  }
100 
101  void new_stroke()
102  {
105  }
106 
107  void set_base_value (int id, float value) {
108  assert (id >= 0 && id < BRUSH_SETTINGS_COUNT);
109  settings[id]->base_value = value;
110 
111  settings_base_values_have_changed ();
112  }
113 
114  void set_mapping_n (int id, int input, int n) {
115  assert (id >= 0 && id < BRUSH_SETTINGS_COUNT);
116  settings[id]->set_n (input, n);
117  }
118 
119  void set_mapping_point (int id, int input, int index, float x, float y) {
120  assert (id >= 0 && id < BRUSH_SETTINGS_COUNT);
121  settings[id]->set_point (input, index, x, y);
122  }
123 
124  float get_state (int i)
125  {
126  assert (i >= 0 && i < STATE_COUNT);
127  return states[i];
128  }
129 
130  void set_state (int i, float value)
131  {
132  assert (i >= 0 && i < STATE_COUNT);
133  states[i] = value;
134  }
135 
136 private:
137  // returns the fraction still left after t seconds
138  float exp_decay (float T_const, float t)
139  {
140  // the argument might not make mathematical sense (whatever.)
141  if (T_const <= 0.001) {
142  return 0.0;
143  } else {
144  return exp(- t / T_const);
145  }
146  }
147 
148 
149  void settings_base_values_have_changed ()
150  {
151  // precalculate stuff that does not change dynamically
152 
153  // Precalculate how the physical speed will be mapped to the speed input value.
154  // The forumla for this mapping is:
155  //
156  // y = log(gamma+x)*m + q;
157  //
158  // x: the physical speed (pixels per basic dab radius)
159  // y: the speed input that will be reported
160  // gamma: parameter set by ths user (small means a logarithmic mapping, big linear)
161  // m, q: parameters to scale and translate the curve
162  //
163  // The code below calculates m and q given gamma and two hardcoded constraints.
164  //
165  for (int i=0; i<2; i++) {
166  float gamma;
167  gamma = settings[(i==0)?BRUSH_SPEED1_GAMMA:BRUSH_SPEED2_GAMMA]->base_value;
168  gamma = exp(gamma);
169 
170  float fix1_x, fix1_y, fix2_x, fix2_dy;
171  fix1_x = 45.0;
172  fix1_y = 0.5;
173  fix2_x = 45.0;
174  fix2_dy = 0.015;
175 
176  float m, q;
177  float c1;
178  c1 = log(fix1_x+gamma);
179  m = fix2_dy * (fix2_x + gamma);
180  q = fix1_y - m*c1;
181 
182  speed_mapping_gamma[i] = gamma;
183  speed_mapping_m[i] = m;
184  speed_mapping_q[i] = q;
185  }
186  }
187 
188  // This function runs a brush "simulation" step. Usually it is
189  // called once or twice per dab. In theory the precision of the
190  // "simulation" gets better when it is called more often. In
191  // practice this only matters if there are some highly nonlinear
192  // mappings in critical places or extremely few events per second.
193  //
194  // note: parameters are is dx/ddab, ..., dtime/ddab (dab is the number, 5.0 = 5th dab)
195  void update_states_and_setting_values (float step_dx, float step_dy, float step_dpressure, float step_declination, float step_ascension, float step_dtime)
196  {
197  float pressure;
198  float inputs[INPUT_COUNT];
199 
200  if (step_dtime < 0.0) {
201  printf("Time is running backwards!\n");
202  step_dtime = 0.001;
203  } else if (step_dtime == 0.0) {
204  // FIXME: happens about every 10th start, workaround (against division by zero)
205  step_dtime = 0.001;
206  }
207 
208  states[STATE_X] += step_dx;
209  states[STATE_Y] += step_dy;
210  states[STATE_PRESSURE] += step_dpressure;
211 
212  states[STATE_DECLINATION] += step_declination;
213  states[STATE_ASCENSION] += step_ascension;
214 
215  float base_radius = expf(settings[BRUSH_RADIUS_LOGARITHMIC]->base_value);
216 
217  // FIXME: does happen (interpolation problem?)
218  states[STATE_PRESSURE] = CLAMP(states[STATE_PRESSURE], 0.0, 1.0);
219  pressure = states[STATE_PRESSURE];
220 
221  { // start / end stroke (for "stroke" input only)
222  if (!states[STATE_STROKE_STARTED]) {
223  if (pressure > settings[BRUSH_STROKE_THRESHOLD]->base_value + 0.0001) {
224  // start new stroke
225  //printf("stroke start %f\n", pressure);
226  states[STATE_STROKE_STARTED] = 1;
227  states[STATE_STROKE] = 0.0;
228  }
229  } else {
230  if (pressure <= settings[BRUSH_STROKE_THRESHOLD]->base_value * 0.9 + 0.0001) {
231  // end stroke
232  //printf("stroke end\n");
233  states[STATE_STROKE_STARTED] = 0;
234  }
235  }
236  }
237 
238  // now follows input handling
239 
240  float norm_dx, norm_dy, norm_dist, norm_speed;
241  norm_dx = step_dx / step_dtime / base_radius;
242  norm_dy = step_dy / step_dtime / base_radius;
243  norm_speed = sqrt(SQR(norm_dx) + SQR(norm_dy));
244  norm_dist = norm_speed * step_dtime;
245 
246  inputs[INPUT_PRESSURE] = pressure;
247  inputs[INPUT_SPEED1] = log(speed_mapping_gamma[0] + states[STATE_NORM_SPEED1_SLOW])*speed_mapping_m[0] + speed_mapping_q[0];
248  inputs[INPUT_SPEED2] = log(speed_mapping_gamma[1] + states[STATE_NORM_SPEED2_SLOW])*speed_mapping_m[1] + speed_mapping_q[1];
249  inputs[INPUT_RANDOM] = g_rand_double (rng);
250  inputs[INPUT_STROKE] = MIN(states[STATE_STROKE], 1.0);
251  inputs[INPUT_DIRECTION] = fmodf (atan2f (states[STATE_DIRECTION_DY], states[STATE_DIRECTION_DX])/(2*M_PI)*360 + 180.0, 180.0);
252  inputs[INPUT_TILT_DECLINATION] = states[STATE_DECLINATION];
253  inputs[INPUT_TILT_ASCENSION] = states[STATE_ASCENSION];
254  inputs[INPUT_CUSTOM] = states[STATE_CUSTOM_INPUT];
255  if (print_inputs) {
256  g_print("press=% 4.3f, speed1=% 4.4f\tspeed2=% 4.4f\tstroke=% 4.3f\tcustom=% 4.3f\n", (double)inputs[INPUT_PRESSURE], (double)inputs[INPUT_SPEED1], (double)inputs[INPUT_SPEED2], (double)inputs[INPUT_STROKE], (double)inputs[INPUT_CUSTOM]);
257  }
258  // FIXME: this one fails!!!
259  //assert(inputs[INPUT_SPEED1] >= 0.0 && inputs[INPUT_SPEED1] < 1e8); // checking for inf
260 
261  for (int i=0; i<BRUSH_SETTINGS_COUNT; i++) {
262  settings_value[i] = settings[i]->calculate (inputs);
263  }
264 
265  {
266  float fac = 1.0 - exp_decay (settings_value[BRUSH_SLOW_TRACKING_PER_DAB], 1.0);
267  states[STATE_ACTUAL_X] += (states[STATE_X] - states[STATE_ACTUAL_X]) * fac; // FIXME: should this depend on base radius?
268  states[STATE_ACTUAL_Y] += (states[STATE_Y] - states[STATE_ACTUAL_Y]) * fac;
269  }
270 
271  { // slow speed
272  float fac;
273  fac = 1.0 - exp_decay (settings_value[BRUSH_SPEED1_SLOWNESS], step_dtime);
274  states[STATE_NORM_SPEED1_SLOW] += (norm_speed - states[STATE_NORM_SPEED1_SLOW]) * fac;
275  fac = 1.0 - exp_decay (settings_value[BRUSH_SPEED2_SLOWNESS], step_dtime);
276  states[STATE_NORM_SPEED2_SLOW] += (norm_speed - states[STATE_NORM_SPEED2_SLOW]) * fac;
277  }
278 
279  { // slow speed, but as vector this time
280 
281  // FIXME: offset_by_speed should be removed.
282  // Is it broken, non-smooth, system-dependent math?!
283  // A replacement could be a directed random offset.
284 
285  float time_constant = exp(settings_value[BRUSH_OFFSET_BY_SPEED_SLOWNESS]*0.01)-1.0;
286  // Workaround for a bug that happens mainly on Windows, causing
287  // individual dabs to be placed far far away. Using the speed
288  // with zero filtering is just asking for trouble anyway.
289  if (time_constant < 0.002) time_constant = 0.002;
290  float fac = 1.0 - exp_decay (time_constant, step_dtime);
291  states[STATE_NORM_DX_SLOW] += (norm_dx - states[STATE_NORM_DX_SLOW]) * fac;
292  states[STATE_NORM_DY_SLOW] += (norm_dy - states[STATE_NORM_DY_SLOW]) * fac;
293  }
294 
295  { // orientation (similar lowpass filter as above, but use dabtime instead of wallclock time)
296  float dx = step_dx / base_radius;
297  float dy = step_dy / base_radius;
298  float step_in_dabtime = hypotf(dx, dy); // FIXME: are we recalculating something here that we already have?
299  float fac = 1.0 - exp_decay (exp(settings_value[BRUSH_DIRECTION_FILTER]*0.5)-1.0, step_in_dabtime);
300 
301  float dx_old = states[STATE_DIRECTION_DX];
302  float dy_old = states[STATE_DIRECTION_DY];
303  // use the opposite speed vector if it is closer (we don't care about 180 degree turns)
304  if (SQR(dx_old-dx) + SQR(dy_old-dy) > SQR(dx_old-(-dx)) + SQR(dy_old-(-dy))) {
305  dx = -dx;
306  dy = -dy;
307  }
308  states[STATE_DIRECTION_DX] += (dx - states[STATE_DIRECTION_DX]) * fac;
309  states[STATE_DIRECTION_DY] += (dy - states[STATE_DIRECTION_DY]) * fac;
310  }
311 
312  { // custom input
313  float fac;
314  fac = 1.0 - exp_decay (settings_value[BRUSH_CUSTOM_INPUT_SLOWNESS], 0.1);
315  states[STATE_CUSTOM_INPUT] += (settings_value[BRUSH_CUSTOM_INPUT] - states[STATE_CUSTOM_INPUT]) * fac;
316  }
317 
318  { // stroke length
319  float frequency;
320  float wrap;
321  frequency = expf(-settings_value[BRUSH_STROKE_DURATION_LOGARITHMIC]);
322  states[STATE_STROKE] += norm_dist * frequency;
323  // can happen, probably caused by rounding
324  if (states[STATE_STROKE] < 0) states[STATE_STROKE] = 0;
325  wrap = 1.0 + settings_value[BRUSH_STROKE_HOLDTIME];
326  if (states[STATE_STROKE] > wrap) {
327  if (wrap > 9.9 + 1.0) {
328  // "inifinity", just hold stroke somewhere >= 1.0
329  states[STATE_STROKE] = 1.0;
330  } else {
331  states[STATE_STROKE] = fmodf(states[STATE_STROKE], wrap);
332  // just in case
333  if (states[STATE_STROKE] < 0) states[STATE_STROKE] = 0;
334  }
335  }
336  }
337 
338  // calculate final radius
339  float radius_log;
340  radius_log = settings_value[BRUSH_RADIUS_LOGARITHMIC];
341  states[STATE_ACTUAL_RADIUS] = expf(radius_log);
344 
345  // aspect ratio (needs to be caluclated here because it can affect the dab spacing)
348  }
349 
350  // Called only from stroke_to(). Calculate everything needed to
351  // draw the dab, then let the surface do the actual drawing.
352  //
353  // This is only gets called right after update_states_and_setting_values().
354  // Returns true if the surface was modified.
355  bool prepare_and_draw_dab (Surface * surface)
356  {
357  float x, y, opaque;
358  float radius;
359 
360  // ensure we don't get a positive result with two negative opaque values
361  if (settings_value[BRUSH_OPAQUE] < 0) settings_value[BRUSH_OPAQUE] = 0;
362  opaque = settings_value[BRUSH_OPAQUE] * settings_value[BRUSH_OPAQUE_MULTIPLY];
363  opaque = CLAMP(opaque, 0.0, 1.0);
364  //if (opaque == 0.0) return false; <-- cannot do that, since we need to update smudge state.
365  if (settings_value[BRUSH_OPAQUE_LINEARIZE]) {
366  // OPTIMIZE: no need to recalculate this for each dab
367  float alpha, beta, alpha_dab, beta_dab;
368  float dabs_per_pixel;
369  // dabs_per_pixel is just estimated roughly, I didn't think hard
370  // about the case when the radius changes during the stroke
371  dabs_per_pixel = (
374  ) * 2.0;
375 
376  // the correction is probably not wanted if the dabs don't overlap
377  if (dabs_per_pixel < 1.0) dabs_per_pixel = 1.0;
378 
379  // interpret the user-setting smoothly
380  dabs_per_pixel = 1.0 + settings[BRUSH_OPAQUE_LINEARIZE]->base_value*(dabs_per_pixel-1.0);
381 
382  // see doc/brushdab_saturation.png
383  // beta = beta_dab^dabs_per_pixel
384  // <==> beta_dab = beta^(1/dabs_per_pixel)
385  alpha = opaque;
386  beta = 1.0-alpha;
387  beta_dab = powf(beta, 1.0/dabs_per_pixel);
388  alpha_dab = 1.0-beta_dab;
389  opaque = alpha_dab;
390  }
391 
392  x = states[STATE_ACTUAL_X];
393  y = states[STATE_ACTUAL_Y];
394 
395  float base_radius = expf(settings[BRUSH_RADIUS_LOGARITHMIC]->base_value);
396 
397  if (settings_value[BRUSH_OFFSET_BY_SPEED]) {
398  x += states[STATE_NORM_DX_SLOW] * settings_value[BRUSH_OFFSET_BY_SPEED] * 0.1 * base_radius;
399  y += states[STATE_NORM_DY_SLOW] * settings_value[BRUSH_OFFSET_BY_SPEED] * 0.1 * base_radius;
400  }
401 
402  if (settings_value[BRUSH_OFFSET_BY_RANDOM]) {
403  float amp = settings_value[BRUSH_OFFSET_BY_RANDOM];
404  if (amp < 0.0) amp = 0.0;
405  x += rand_gauss (rng) * amp * base_radius;
406  y += rand_gauss (rng) * amp * base_radius;
407  }
408 
409 
410  radius = states[STATE_ACTUAL_RADIUS];
411  if (settings_value[BRUSH_RADIUS_BY_RANDOM]) {
412  float radius_log, alpha_correction;
413  // go back to logarithmic radius to add the noise
414  radius_log = settings_value[BRUSH_RADIUS_LOGARITHMIC];
415  radius_log += rand_gauss (rng) * settings_value[BRUSH_RADIUS_BY_RANDOM];
416  radius = expf(radius_log);
417  radius = CLAMP(radius, ACTUAL_RADIUS_MIN, ACTUAL_RADIUS_MAX);
418  alpha_correction = states[STATE_ACTUAL_RADIUS] / radius;
419  alpha_correction = SQR(alpha_correction);
420  if (alpha_correction <= 1.0) {
421  opaque *= alpha_correction;
422  }
423  }
424 
425  // color part
426 
427  float color_h = settings[BRUSH_COLOR_H]->base_value;
428  float color_s = settings[BRUSH_COLOR_S]->base_value;
429  float color_v = settings[BRUSH_COLOR_V]->base_value;
430  float eraser_target_alpha = 1.0;
431  if (settings_value[BRUSH_SMUDGE] > 0.0) {
432  // mix (in RGB) the smudge color with the brush color
433  hsv_to_rgb_float (&color_h, &color_s, &color_v);
434  float fac = settings_value[BRUSH_SMUDGE];
435  if (fac > 1.0) fac = 1.0;
436  // If the smudge color somewhat transparent, then the resulting
437  // dab will do erasing towards that transparency level.
438  // see also ../doc/smudge_math.png
439  eraser_target_alpha = (1-fac)*1.0 + fac*states[STATE_SMUDGE_A];
440  // fix rounding errors (they really seem to happen in the previous line)
441  eraser_target_alpha = CLAMP(eraser_target_alpha, 0.0, 1.0);
442  if (eraser_target_alpha > 0) {
443  color_h = (fac*states[STATE_SMUDGE_RA] + (1-fac)*color_h) / eraser_target_alpha;
444  color_s = (fac*states[STATE_SMUDGE_GA] + (1-fac)*color_s) / eraser_target_alpha;
445  color_v = (fac*states[STATE_SMUDGE_BA] + (1-fac)*color_v) / eraser_target_alpha;
446  } else {
447  // we are only erasing; the color does not matter
448  color_h = 1.0;
449  color_s = 0.0;
450  color_v = 0.0;
451  }
452  rgb_to_hsv_float (&color_h, &color_s, &color_v);
453  }
454 
455  if (settings_value[BRUSH_SMUDGE_LENGTH] < 1.0 and
456  // optimization, since normal brushes have smudge_length == 0.5 without actually smudging
457  (settings_value[BRUSH_SMUDGE] != 0.0 or not settings[BRUSH_SMUDGE]->is_constant())) {
458 
459  float fac = settings_value[BRUSH_SMUDGE_LENGTH];
460  if (fac < 0.01) fac = 0.01;
461  int px, py;
462  px = ROUND(x);
463  py = ROUND(y);
464 
465  // Calling get_color() is almost as expensive as rendering a
466  // dab. Because of this we use the previous value if it is not
467  // expected to hurt quality too much. We call it at most every
468  // second dab.
469  float r, g, b, a;
470  states[STATE_LAST_GETCOLOR_RECENTNESS] *= fac;
471  if (states[STATE_LAST_GETCOLOR_RECENTNESS] < 0.5*fac) {
472  states[STATE_LAST_GETCOLOR_RECENTNESS] = 1.0;
473 
474  float smudge_radius = radius * expf(settings_value[BRUSH_SMUDGE_RADIUS_LOG]);
475  smudge_radius = CLAMP(smudge_radius, ACTUAL_RADIUS_MIN, ACTUAL_RADIUS_MAX);
476  surface->get_color (px, py, smudge_radius, &r, &g, &b, &a);
477 
478  states[STATE_LAST_GETCOLOR_R] = r;
479  states[STATE_LAST_GETCOLOR_G] = g;
480  states[STATE_LAST_GETCOLOR_B] = b;
481  states[STATE_LAST_GETCOLOR_A] = a;
482  } else {
483  r = states[STATE_LAST_GETCOLOR_R];
484  g = states[STATE_LAST_GETCOLOR_G];
485  b = states[STATE_LAST_GETCOLOR_B];
486  a = states[STATE_LAST_GETCOLOR_A];
487  }
488 
489  // updated the smudge color (stored with premultiplied alpha)
490  states[STATE_SMUDGE_A ] = fac*states[STATE_SMUDGE_A ] + (1-fac)*a;
491  // fix rounding errors
492  states[STATE_SMUDGE_A ] = CLAMP(states[STATE_SMUDGE_A], 0.0, 1.0);
493 
494  states[STATE_SMUDGE_RA] = fac*states[STATE_SMUDGE_RA] + (1-fac)*r*a;
495  states[STATE_SMUDGE_GA] = fac*states[STATE_SMUDGE_GA] + (1-fac)*g*a;
496  states[STATE_SMUDGE_BA] = fac*states[STATE_SMUDGE_BA] + (1-fac)*b*a;
497  }
498 
499  // eraser
500  if (settings_value[BRUSH_ERASER]) {
501  eraser_target_alpha *= (1.0-settings_value[BRUSH_ERASER]);
502  }
503 
504  // HSV color change
505  color_h += settings_value[BRUSH_CHANGE_COLOR_H];
506  color_s += settings_value[BRUSH_CHANGE_COLOR_HSV_S];
507  color_v += settings_value[BRUSH_CHANGE_COLOR_V];
508 
509  // HSL color change
510  if (settings_value[BRUSH_CHANGE_COLOR_L] || settings_value[BRUSH_CHANGE_COLOR_HSL_S]) {
511  // (calculating way too much here, can be optimized if neccessary)
512  // this function will CLAMP the inputs
513  hsv_to_rgb_float (&color_h, &color_s, &color_v);
514  rgb_to_hsl_float (&color_h, &color_s, &color_v);
515  color_v += settings_value[BRUSH_CHANGE_COLOR_L];
516  color_s += settings_value[BRUSH_CHANGE_COLOR_HSL_S];
517  hsl_to_rgb_float (&color_h, &color_s, &color_v);
518  rgb_to_hsv_float (&color_h, &color_s, &color_v);
519  }
520 
521  float hardness = CLAMP(settings_value[BRUSH_HARDNESS], 0.0, 1.0);
522 
523  // anti-aliasing attempt (works surprisingly well for ink brushes)
524  float current_fadeout_in_pixels = radius * (1.0 - hardness);
525  float min_fadeout_in_pixels = settings_value[BRUSH_ANTI_ALIASING];
526  if (current_fadeout_in_pixels < min_fadeout_in_pixels) {
527  // need to soften the brush (decrease hardness), but keep optical radius
528  // so we tune both radius and hardness, to get the desired fadeout_in_pixels
529  float current_optical_radius = radius - (1.0-hardness)*radius/2.0;
530 
531  // Equation 1: (new fadeout must be equal to min_fadeout)
532  // min_fadeout_in_pixels = radius_new*(1.0 - hardness_new)
533  // Equation 2: (optical radius must remain unchanged)
534  // current_optical_radius = radius_new - (1.0-hardness_new)*radius_new/2.0
535  //
536  // Solved Equation 1 for hardness_new, using Equation 2: (thanks to mathomatic)
537  float hardness_new = ((current_optical_radius - (min_fadeout_in_pixels/2.0))/(current_optical_radius + (min_fadeout_in_pixels/2.0)));
538  // Using Equation 1:
539  float radius_new = (min_fadeout_in_pixels/(1.0 - hardness_new));
540 
541  hardness = hardness_new;
542  radius = radius_new;
543  }
544 
545  // the functions below will CLAMP most inputs
546  hsv_to_rgb_float (&color_h, &color_s, &color_v);
547  return surface->draw_dab (x, y, radius, color_h, color_s, color_v, opaque, hardness, eraser_target_alpha,
549  settings_value[BRUSH_LOCK_ALPHA]);
550  }
551 
552  // How many dabs will be drawn between the current and the next (x, y, pressure, +dt) position?
553  // WARNING: pressure is not used
554  float count_dabs_to (float x, float y, float pressure, float dt)
555  {
556  float xx, yy;
557  float res1, res2, res3;
558  float dist;
559 
560  if (states[STATE_ACTUAL_RADIUS] == 0.0) states[STATE_ACTUAL_RADIUS] = expf(settings[BRUSH_RADIUS_LOGARITHMIC]->base_value);
563 
564 
565  // OPTIMIZE: expf() called too often
566  float base_radius = expf(settings[BRUSH_RADIUS_LOGARITHMIC]->base_value);
567  if (base_radius < ACTUAL_RADIUS_MIN) base_radius = ACTUAL_RADIUS_MIN;
568  if (base_radius > ACTUAL_RADIUS_MAX) base_radius = ACTUAL_RADIUS_MAX;
569  //if (base_radius < 0.5) base_radius = 0.5;
570  //if (base_radius > 500.0) base_radius = 500.0;
571 
572  xx = x - states[STATE_X];
573  yy = y - states[STATE_Y];
574  //dp = pressure - pressure; // Not useful?
575  // TODO: control rate with pressure (dabs per pressure) (dpressure is useless)
576 
577  if (states[STATE_ACTUAL_ELLIPTICAL_DAB_RATIO] > 1.0) {
578  // code duplication, see tiledsurface::draw_dab()
579  float angle_rad=states[STATE_ACTUAL_ELLIPTICAL_DAB_ANGLE]/360*2*M_PI;
580  float cs=cos(angle_rad);
581  float sn=sin(angle_rad);
582  float yyr=(yy*cs-xx*sn)*states[STATE_ACTUAL_ELLIPTICAL_DAB_RATIO];
583  float xxr=yy*sn+xx*cs;
584  dist = sqrt(yyr*yyr + xxr*xxr);
585  } else {
586  dist = hypotf(xx, yy);
587  }
588 
589  // FIXME: no need for base_value or for the range checks above IF always the interpolation
590  // function will be called before this one
591  res1 = dist / states[STATE_ACTUAL_RADIUS] * settings[BRUSH_DABS_PER_ACTUAL_RADIUS]->base_value;
592  res2 = dist / base_radius * settings[BRUSH_DABS_PER_BASIC_RADIUS]->base_value;
593  res3 = dt * settings[BRUSH_DABS_PER_SECOND]->base_value;
594  return res1 + res2 + res3;
595  }
596 
597 public:
598  // This function:
599  // - is called once for each motion event
600  // - does motion event interpolation
601  // - paints zero, one or several dabs
602  // - decides whether the stroke is finished (for undo/redo)
603  // returns true if the stroke is finished or empty
604  bool stroke_to (Surface * surface, float x, float y, float pressure, float xtilt, float ytilt, double dtime)
605  {
606  //printf("%f %f %f %f\n", (double)dtime, (double)x, (double)y, (double)pressure);
607 
608  float tilt_ascension = 0.0;
609  float tilt_declination = 90.0;
610  if (xtilt != 0 || ytilt != 0) {
611  // shield us from insane tilt input
612  xtilt = CLAMP(xtilt, -1.0, 1.0);
613  ytilt = CLAMP(ytilt, -1.0, 1.0);
614  assert(std::isfinite(xtilt) && std::isfinite(ytilt));
615 
616  tilt_ascension = 180.0*atan2(-xtilt, ytilt)/M_PI;
617  float e;
618  if (abs(xtilt) > abs(ytilt)) {
619  e = sqrt(1+ytilt*ytilt);
620  } else {
621  e = sqrt(1+xtilt*xtilt);
622  }
623  float rad = hypot(xtilt, ytilt);
624  float cos_alpha = rad/e;
625  if (cos_alpha >= 1.0) cos_alpha = 1.0; // fix numerical inaccuracy
626  tilt_declination = 180.0*acos(cos_alpha)/M_PI;
627 
628  assert(std::isfinite(tilt_ascension));
629  assert(std::isfinite(tilt_declination));
630  }
631 
632  // printf("xtilt %f, ytilt %f\n", (double)xtilt, (double)ytilt);
633  // printf("ascension %f, declination %f\n", (double)tilt_ascension, (double)tilt_declination);
634 
635  pressure = CLAMP(pressure, 0.0, 1.0);
636  if (!std::isfinite(x) || !std::isfinite(y) ||
637  (x > 1e10 || y > 1e10 || x < -1e10 || y < -1e10)) {
638  // workaround attempt for https://gna.org/bugs/?14372
639  g_print("Warning: ignoring brush::stroke_to with insane inputs (x = %f, y = %f)\n", (double)x, (double)y);
640  x = 0.0;
641  y = 0.0;
642  pressure = 0.0;
643  }
644  // the assertion below is better than out-of-memory later at save time
645  assert(x < 1e8 && y < 1e8 && x > -1e8 && y > -1e8);
646 
647  if (dtime < 0) g_print("Time jumped backwards by dtime=%f seconds!\n", dtime);
648  if (dtime <= 0) dtime = 0.0001; // protect against possible division by zero bugs
649 
650  if (dtime > 0.100 && pressure && states[STATE_PRESSURE] == 0) {
651  // Workaround for tablets that don't report motion events without pressure.
652  // This is to avoid linear interpolation of the pressure between two events.
653  stroke_to (surface, x, y, 0.0, 90.0, 0.0, dtime-0.0001);
654  dtime = 0.0001;
655  }
656 
657  g_rand_set_seed (rng, states[STATE_RNG_SEED]);
658 
659  { // calculate the actual "virtual" cursor position
660 
661  // noise first
662  if (settings[BRUSH_TRACKING_NOISE]->base_value) {
663  // OPTIMIZE: expf() called too often
664  float base_radius = expf(settings[BRUSH_RADIUS_LOGARITHMIC]->base_value);
665 
666  x += rand_gauss (rng) * settings[BRUSH_TRACKING_NOISE]->base_value * base_radius;
667  y += rand_gauss (rng) * settings[BRUSH_TRACKING_NOISE]->base_value * base_radius;
668  }
669 
670  float fac = 1.0 - exp_decay (settings[BRUSH_SLOW_TRACKING]->base_value, 100.0*dtime);
671  x = states[STATE_X] + (x - states[STATE_X]) * fac;
672  y = states[STATE_Y] + (y - states[STATE_Y]) * fac;
673  }
674 
675  // draw many (or zero) dabs to the next position
676 
677  // see doc/stroke2dabs.png
678  float dist_moved = states[STATE_DIST];
679  float dist_todo = count_dabs_to (x, y, pressure, dtime);
680 
681  //if (dtime > 5 || dist_todo > 300) {
682  if (dtime > 5 || reset_requested) {
683  reset_requested = false;
684 
685  /*
686  TODO:
687  if (dist_todo > 300) {
688  // this happens quite often, eg when moving the cursor back into the window
689  // FIXME: bad to hardcode a distance treshold here - might look at zoomed image
690  // better detect leaving/entering the window and reset then.
691  g_print ("Warning: NOT drawing %f dabs.\n", dist_todo);
692  g_print ("dtime=%f, dx=%f\n", dtime, x-states[STATE_X]);
693  //must_reset = 1;
694  }
695  */
696 
697  //printf("Brush reset.\n");
698  for (int i=0; i<STATE_COUNT; i++) {
699  states[i] = 0;
700  }
701 
702  states[STATE_X] = x;
703  states[STATE_Y] = y;
704  states[STATE_PRESSURE] = pressure;
705 
706  // not resetting, because they will get overwritten below:
707  //dx, dy, dpress, dtime
708 
709  states[STATE_ACTUAL_X] = states[STATE_X];
710  states[STATE_ACTUAL_Y] = states[STATE_Y];
711  states[STATE_STROKE] = 1.0; // start in a state as if the stroke was long finished
712 
713  return true;
714  }
715 
716  //g_print("dist = %f\n", states[STATE_DIST]);
717  enum { UNKNOWN, YES, NO } painted = UNKNOWN;
718  double dtime_left = dtime;
719 
720  float step_dx, step_dy, step_dpressure, step_dtime;
721  float step_declination, step_ascension;
722  while (dist_moved + dist_todo >= 1.0) { // there are dabs pending
723  { // linear interpolation (nonlinear variant was too slow, see SVN log)
724  float frac; // fraction of the remaining distance to move
725  if (dist_moved > 0) {
726  // "move" the brush exactly to the first dab (moving less than one dab)
727  frac = (1.0 - dist_moved) / dist_todo;
728  dist_moved = 0;
729  } else {
730  // "move" the brush from one dab to the next
731  frac = 1.0 / dist_todo;
732  }
733  step_dx = frac * (x - states[STATE_X]);
734  step_dy = frac * (y - states[STATE_Y]);
735  step_dpressure = frac * (pressure - states[STATE_PRESSURE]);
736  step_dtime = frac * (dtime_left - 0.0);
737  step_declination = frac * (tilt_declination - states[STATE_DECLINATION]);
738  step_ascension = frac * (tilt_ascension - states[STATE_ASCENSION]);
739  // Though it looks different, time is interpolated exactly like x/y/pressure.
740  }
741 
742  update_states_and_setting_values (step_dx, step_dy, step_dpressure, step_declination, step_ascension, step_dtime);
743  bool painted_now = prepare_and_draw_dab (surface);
744  if (painted_now) {
745  painted = YES;
746  } else if (painted == UNKNOWN) {
747  painted = NO;
748  }
749 
750  dtime_left -= step_dtime;
751  dist_todo = count_dabs_to (x, y, pressure, dtime_left);
752  }
753 
754  {
755  // "move" the brush to the current time (no more dab will happen)
756  // Important to do this at least once every event, because
757  // brush_count_dabs_to depends on the radius and the radius can
758  // depend on something that changes much faster than only every
759  // dab (eg speed).
760 
761  step_dx = x - states[STATE_X];
762  step_dy = y - states[STATE_Y];
763  step_dpressure = pressure - states[STATE_PRESSURE];
764  step_declination = tilt_declination - states[STATE_DECLINATION];
765  step_ascension = tilt_ascension - states[STATE_ASCENSION];
766  step_dtime = dtime_left;
767 
768  //dtime_left = 0; but that value is not used any more
769 
770  update_states_and_setting_values (step_dx, step_dy, step_dpressure, step_declination, step_ascension, step_dtime);
771  }
772 
773  // save the fraction of a dab that is already done now
774  states[STATE_DIST] = dist_moved + dist_todo;
775  //g_print("dist_final = %f\n", states[STATE_DIST]);
776 
777  // next seed for the RNG (GRand has no get_state() and states[] must always contain our full state)
778  states[STATE_RNG_SEED] = g_rand_int(rng);
779 
780  // stroke separation logic (for undo/redo)
781 
782  if (painted == UNKNOWN) {
784  // still idling
785  painted = NO;
786  } else {
787  // probably still painting (we get more events than brushdabs)
788  painted = YES;
789  //if (pressure == 0) g_print ("info: assuming 'still painting' while there is no pressure\n");
790  }
791  }
792  if (painted == YES) {
793  //if (stroke_current_idling_time > 0) g_print ("idling ==> painting\n");
796  // force a stroke split after some time
797  if (stroke_total_painting_time > 4 + 3*pressure) {
798  // but only if pressure is not being released
799  // FIXME: use some smoothed state for dpressure, not the output of the interpolation code
800  // (which might easily wrongly give dpressure == 0)
801  if (step_dpressure >= 0) {
802  return true;
803  }
804  }
805  } else if (painted == NO) {
806  //if (stroke_current_idling_time == 0) g_print ("painting ==> idling\n");
808  if (stroke_total_painting_time == 0) {
809  // not yet painted, start a new stroke if we have accumulated a lot of irrelevant motion events
810  if (stroke_current_idling_time > 1.0) {
811  return true;
812  }
813  } else {
814  // Usually we have pressure==0 here. But some brushes can paint
815  // nothing at full pressure (eg gappy lines, or a stroke that
816  // fades out). In either case this is the prefered moment to split.
818  return true;
819  }
820  }
821  }
822  return false;
823  }
824 
825 };
826 
827 }