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) 49 double stroke_total_painting_time; 50 double stroke_current_idling_time; 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: Brush()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 ~Brush()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 reset()96 void reset() 97 { 98 reset_requested = true; 99 } 100 new_stroke()101 void new_stroke() 102 { 103 stroke_current_idling_time = 0; 104 stroke_total_painting_time = 0; 105 } 106 set_base_value(int id,float value)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 set_mapping_n(int id,int input,int n)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 set_mapping_point(int id,int input,int index,float x,float y)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 get_state(int i)124 float get_state (int i) 125 { 126 assert (i >= 0 && i < STATE_COUNT); 127 return states[i]; 128 } 129 set_state(int i,float value)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 exp_decay(float T_const,float t)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 settings_base_values_have_changed()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) update_states_and_setting_values(float step_dx,float step_dy,float step_dpressure,float step_declination,float step_ascension,float step_dtime)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); 342 if (states[STATE_ACTUAL_RADIUS] < ACTUAL_RADIUS_MIN) states[STATE_ACTUAL_RADIUS] = ACTUAL_RADIUS_MIN; 343 if (states[STATE_ACTUAL_RADIUS] > ACTUAL_RADIUS_MAX) states[STATE_ACTUAL_RADIUS] = ACTUAL_RADIUS_MAX; 344 345 // aspect ratio (needs to be caluclated here because it can affect the dab spacing) 346 states[STATE_ACTUAL_ELLIPTICAL_DAB_RATIO] = settings_value[BRUSH_ELLIPTICAL_DAB_RATIO]; 347 states[STATE_ACTUAL_ELLIPTICAL_DAB_ANGLE] = settings_value[BRUSH_ELLIPTICAL_DAB_ANGLE]; 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. prepare_and_draw_dab(Surface * surface)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 = ( 372 settings[BRUSH_DABS_PER_ACTUAL_RADIUS]->base_value + 373 settings[BRUSH_DABS_PER_BASIC_RADIUS]->base_value 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, 548 states[STATE_ACTUAL_ELLIPTICAL_DAB_RATIO], states[STATE_ACTUAL_ELLIPTICAL_DAB_ANGLE], 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 count_dabs_to(float x,float y,float pressure,float dt)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); 561 if (states[STATE_ACTUAL_RADIUS] < ACTUAL_RADIUS_MIN) states[STATE_ACTUAL_RADIUS] = ACTUAL_RADIUS_MIN; 562 if (states[STATE_ACTUAL_RADIUS] > ACTUAL_RADIUS_MAX) states[STATE_ACTUAL_RADIUS] = ACTUAL_RADIUS_MAX; 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 stroke_to(Surface * surface,float x,float y,float pressure,float xtilt,float ytilt,double dtime)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) { 783 if (stroke_current_idling_time > 0 || stroke_total_painting_time == 0) { 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"); 794 stroke_total_painting_time += dtime; 795 stroke_current_idling_time = 0; 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"); 807 stroke_current_idling_time += dtime; 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. 817 if (stroke_total_painting_time+stroke_current_idling_time > 0.9 + 5*pressure) { 818 return true; 819 } 820 } 821 } 822 return false; 823 } 824 825 }; 826 827 } 828