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
67 float speed_mapping_gamma[2], speed_mapping_m[2], speed_mapping_q[2];
84 settings_base_values_have_changed();
86 reset_requested =
true;
93 g_rand_free (rng); rng = NULL;
98 reset_requested =
true;
111 settings_base_values_have_changed ();
116 settings[id]->
set_n (input, n);
121 settings[id]->
set_point (input, index, x, y);
138 float exp_decay (
float T_const,
float t)
141 if (T_const <= 0.001) {
144 return exp(- t / T_const);
149 void settings_base_values_have_changed ()
165 for (
int i=0; i<2; i++) {
170 float fix1_x, fix1_y, fix2_x, fix2_dy;
178 c1 = log(fix1_x+gamma);
179 m = fix2_dy * (fix2_x + gamma);
182 speed_mapping_gamma[i] = gamma;
183 speed_mapping_m[i] = m;
184 speed_mapping_q[i] = q;
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)
200 if (step_dtime < 0.0) {
201 printf(
"Time is running backwards!\n");
203 }
else if (step_dtime == 0.0) {
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;
262 settings_value[i] = settings[i]->
calculate (inputs);
289 if (time_constant < 0.002) time_constant = 0.002;
290 float fac = 1.0 - exp_decay (time_constant, step_dtime);
296 float dx = step_dx / base_radius;
297 float dy = step_dy / base_radius;
298 float step_in_dabtime = hypotf(dx, dy);
304 if (
SQR(dx_old-dx) +
SQR(dy_old-dy) >
SQR(dx_old-(-dx)) +
SQR(dy_old-(-dy))) {
327 if (wrap > 9.9 + 1.0) {
355 bool prepare_and_draw_dab (Surface * surface)
363 opaque = CLAMP(opaque, 0.0, 1.0);
367 float alpha, beta, alpha_dab, beta_dab;
368 float dabs_per_pixel;
377 if (dabs_per_pixel < 1.0) dabs_per_pixel = 1.0;
387 beta_dab = powf(beta, 1.0/dabs_per_pixel);
388 alpha_dab = 1.0-beta_dab;
404 if (amp < 0.0) amp = 0.0;
412 float radius_log, alpha_correction;
416 radius = expf(radius_log);
419 alpha_correction =
SQR(alpha_correction);
420 if (alpha_correction <= 1.0) {
421 opaque *= alpha_correction;
430 float eraser_target_alpha = 1.0;
435 if (fac > 1.0) fac = 1.0;
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;
460 if (fac < 0.01) fac = 0.01;
476 surface->get_color (px, py, smudge_radius, &r, &g, &b, &a);
501 eraser_target_alpha *= (1.0-settings_value[
BRUSH_ERASER]);
524 float current_fadeout_in_pixels = radius * (1.0 - hardness);
526 if (current_fadeout_in_pixels < min_fadeout_in_pixels) {
529 float current_optical_radius = radius - (1.0-hardness)*radius/2.0;
537 float hardness_new = ((current_optical_radius - (min_fadeout_in_pixels/2.0))/(current_optical_radius + (min_fadeout_in_pixels/2.0)));
539 float radius_new = (min_fadeout_in_pixels/(1.0 - hardness_new));
541 hardness = hardness_new;
547 return surface->draw_dab (x, y, radius, color_h, color_s, color_v, opaque, hardness, eraser_target_alpha,
554 float count_dabs_to (
float x,
float y,
float pressure,
float dt)
557 float res1, res2, res3;
580 float cs=cos(angle_rad);
581 float sn=sin(angle_rad);
583 float xxr=yy*sn+xx*cs;
584 dist = sqrt(yyr*yyr + xxr*xxr);
586 dist = hypotf(xx, yy);
594 return res1 + res2 + res3;
604 bool stroke_to (
Surface * surface,
float x,
float y,
float pressure,
float xtilt,
float ytilt,
double dtime)
608 float tilt_ascension = 0.0;
609 float tilt_declination = 90.0;
610 if (xtilt != 0 || ytilt != 0) {
612 xtilt = CLAMP(xtilt, -1.0, 1.0);
613 ytilt = CLAMP(ytilt, -1.0, 1.0);
614 assert(std::isfinite(xtilt) && std::isfinite(ytilt));
616 tilt_ascension = 180.0*atan2(-xtilt, ytilt)/M_PI;
618 if (abs(xtilt) > abs(ytilt)) {
619 e = sqrt(1+ytilt*ytilt);
621 e = sqrt(1+xtilt*xtilt);
623 float rad = hypot(xtilt, ytilt);
624 float cos_alpha = rad/e;
625 if (cos_alpha >= 1.0) cos_alpha = 1.0;
626 tilt_declination = 180.0*acos(cos_alpha)/M_PI;
628 assert(std::isfinite(tilt_ascension));
629 assert(std::isfinite(tilt_declination));
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)) {
639 g_print(
"Warning: ignoring brush::stroke_to with insane inputs (x = %f, y = %f)\n", (
double)x, (
double)y);
645 assert(x < 1e8 && y < 1e8 && x > -1e8 && y > -1e8);
647 if (dtime < 0) g_print(
"Time jumped backwards by dtime=%f seconds!\n", dtime);
648 if (dtime <= 0) dtime = 0.0001;
653 stroke_to (surface, x, y, 0.0, 90.0, 0.0, dtime-0.0001);
679 float dist_todo = count_dabs_to (x, y, pressure, dtime);
682 if (dtime > 5 || reset_requested) {
683 reset_requested =
false;
717 enum { UNKNOWN, YES, NO } painted = UNKNOWN;
718 double dtime_left = dtime;
720 float step_dx, step_dy, step_dpressure, step_dtime;
721 float step_declination, step_ascension;
722 while (dist_moved + dist_todo >= 1.0) {
725 if (dist_moved > 0) {
727 frac = (1.0 - dist_moved) / dist_todo;
731 frac = 1.0 / dist_todo;
733 step_dx = frac * (x - states[
STATE_X]);
734 step_dy = frac * (y - states[
STATE_Y]);
736 step_dtime = frac * (dtime_left - 0.0);
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);
746 }
else if (painted == UNKNOWN) {
750 dtime_left -= step_dtime;
751 dist_todo = count_dabs_to (x, y, pressure, dtime_left);
766 step_dtime = dtime_left;
770 update_states_and_setting_values (step_dx, step_dy, step_dpressure, step_declination, step_ascension, step_dtime);
782 if (painted == UNKNOWN) {
792 if (painted == YES) {
801 if (step_dpressure >= 0) {
805 }
else if (painted == NO) {