gimpdynamicsoutput.c 22.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995-1999 Spencer Kimball and Peter Mattis
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
15
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16 17 18 19
 */

#include "config.h"

20
#include <gdk-pixbuf/gdk-pixbuf.h>
21 22 23 24 25 26 27
#include <gegl.h>

#include "libgimpmath/gimpmath.h"
#include "libgimpconfig/gimpconfig.h"

#include "core-types.h"

28 29 30
#include "paint/gimppaintoptions.h"


31
#include "gimpcurve.h"
Alexia Death's avatar
Alexia Death committed
32 33
#include "gimpcurve-map.h"

34 35 36 37 38
#include "gimpdynamicsoutput.h"

#include "gimp-intl.h"


39 40 41 42
#define DEFAULT_USE_PRESSURE  FALSE
#define DEFAULT_USE_VELOCITY  FALSE
#define DEFAULT_USE_DIRECTION FALSE
#define DEFAULT_USE_TILT      FALSE
43
#define DEFAULT_USE_WHEEL     FALSE
44 45
#define DEFAULT_USE_RANDOM    FALSE
#define DEFAULT_USE_FADE      FALSE
46 47 48 49 50 51


enum
{
  PROP_0,

52
  PROP_TYPE,
53 54 55 56
  PROP_USE_PRESSURE,
  PROP_USE_VELOCITY,
  PROP_USE_DIRECTION,
  PROP_USE_TILT,
57
  PROP_USE_WHEEL,
58
  PROP_USE_RANDOM,
Alexia Death's avatar
Alexia Death committed
59 60 61 62 63
  PROP_USE_FADE,
  PROP_PRESSURE_CURVE,
  PROP_VELOCITY_CURVE,
  PROP_DIRECTION_CURVE,
  PROP_TILT_CURVE,
64
  PROP_WHEEL_CURVE,
Alexia Death's avatar
Alexia Death committed
65 66
  PROP_RANDOM_CURVE,
  PROP_FADE_CURVE
67 68 69
};


70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
typedef struct _GimpDynamicsOutputPrivate GimpDynamicsOutputPrivate;

struct _GimpDynamicsOutputPrivate
{
  GimpDynamicsOutputType  type;

  gboolean                use_pressure;
  gboolean                use_velocity;
  gboolean                use_direction;
  gboolean                use_tilt;
  gboolean                use_wheel;
  gboolean                use_random;
  gboolean                use_fade;

  GimpCurve              *pressure_curve;
  GimpCurve              *velocity_curve;
  GimpCurve              *direction_curve;
  GimpCurve              *tilt_curve;
  GimpCurve              *wheel_curve;
  GimpCurve              *random_curve;
  GimpCurve              *fade_curve;
};

#define GET_PRIVATE(output) \
94
        ((GimpDynamicsOutputPrivate *) gimp_dynamics_output_get_instance_private ((GimpDynamicsOutput *) (output)))
95 96


97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
static void   gimp_dynamics_output_finalize     (GObject           *object);
static void   gimp_dynamics_output_set_property (GObject           *object,
                                                 guint              property_id,
                                                 const GValue      *value,
                                                 GParamSpec        *pspec);
static void   gimp_dynamics_output_get_property (GObject           *object,
                                                 guint              property_id,
                                                 GValue            *value,
                                                 GParamSpec        *pspec);
static void   gimp_dynamics_output_copy_curve   (GimpCurve          *src,
                                                 GimpCurve          *dest);

static GimpCurve *
              gimp_dynamics_output_create_curve (GimpDynamicsOutput *output,
                                                 const gchar        *name);
112
static void   gimp_dynamics_output_curve_dirty  (GimpCurve          *curve,
113 114
                                                 GimpDynamicsOutput *output);

115

116 117
G_DEFINE_TYPE_WITH_CODE (GimpDynamicsOutput, gimp_dynamics_output,
                         GIMP_TYPE_OBJECT,
118
                         G_ADD_PRIVATE (GimpDynamicsOutput)
119
                         G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG, NULL))
120 121 122 123 124 125 126 127 128 129 130 131 132

#define parent_class gimp_dynamics_output_parent_class


static void
gimp_dynamics_output_class_init (GimpDynamicsOutputClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->finalize     = gimp_dynamics_output_finalize;
  object_class->set_property = gimp_dynamics_output_set_property;
  object_class->get_property = gimp_dynamics_output_get_property;

133 134 135 136 137 138 139 140
  g_object_class_install_property (object_class, PROP_TYPE,
                                   g_param_spec_enum ("type", NULL,
                                                      _("Output type"),
                                                      GIMP_TYPE_DYNAMICS_OUTPUT_TYPE,
                                                      GIMP_DYNAMICS_OUTPUT_OPACITY,
                                                      GIMP_PARAM_READWRITE |
                                                      G_PARAM_CONSTRUCT));

141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
  GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_USE_PRESSURE,
                            "use-pressure",
                            NULL, NULL,
                            DEFAULT_USE_PRESSURE,
                            GIMP_PARAM_STATIC_STRINGS);

  GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_USE_VELOCITY,
                            "use-velocity",
                            NULL, NULL,
                            DEFAULT_USE_VELOCITY,
                            GIMP_PARAM_STATIC_STRINGS);

  GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_USE_DIRECTION,
                            "use-direction",
                            NULL, NULL,
                            DEFAULT_USE_DIRECTION,
                            GIMP_PARAM_STATIC_STRINGS);

  GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_USE_TILT,
                            "use-tilt",
                            NULL, NULL,
                            DEFAULT_USE_TILT,
                            GIMP_PARAM_STATIC_STRINGS);

  GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_USE_WHEEL,
                            "use-wheel",
                            NULL, NULL,
                            DEFAULT_USE_TILT,
                            GIMP_PARAM_STATIC_STRINGS);

  GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_USE_RANDOM,
                            "use-random",
                            NULL, NULL,
                            DEFAULT_USE_RANDOM,
                            GIMP_PARAM_STATIC_STRINGS);

  GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_USE_FADE,
                            "use-fade",
                            NULL, NULL,
                            DEFAULT_USE_FADE,
                            GIMP_PARAM_STATIC_STRINGS);

  GIMP_CONFIG_PROP_OBJECT (object_class, PROP_PRESSURE_CURVE,
                           "pressure-curve",
                            NULL, NULL,
                           GIMP_TYPE_CURVE,
                           GIMP_CONFIG_PARAM_AGGREGATE);

  GIMP_CONFIG_PROP_OBJECT (object_class, PROP_VELOCITY_CURVE,
                           "velocity-curve",
                            NULL, NULL,
                           GIMP_TYPE_CURVE,
                           GIMP_CONFIG_PARAM_AGGREGATE);

  GIMP_CONFIG_PROP_OBJECT (object_class, PROP_DIRECTION_CURVE,
                           "direction-curve",
                            NULL, NULL,
                           GIMP_TYPE_CURVE,
                           GIMP_CONFIG_PARAM_AGGREGATE);

  GIMP_CONFIG_PROP_OBJECT (object_class, PROP_TILT_CURVE,
                           "tilt-curve",
                            NULL, NULL,
                           GIMP_TYPE_CURVE,
                           GIMP_CONFIG_PARAM_AGGREGATE);

  GIMP_CONFIG_PROP_OBJECT (object_class, PROP_WHEEL_CURVE,
                           "wheel-curve",
                            NULL, NULL,
                           GIMP_TYPE_CURVE,
                           GIMP_CONFIG_PARAM_AGGREGATE);

  GIMP_CONFIG_PROP_OBJECT (object_class, PROP_RANDOM_CURVE,
                           "random-curve",
                            NULL, NULL,
                           GIMP_TYPE_CURVE,
                           GIMP_CONFIG_PARAM_AGGREGATE);

  GIMP_CONFIG_PROP_OBJECT (object_class, PROP_FADE_CURVE,
                           "fade-curve",
                            NULL, NULL,
                           GIMP_TYPE_CURVE,
                           GIMP_CONFIG_PARAM_AGGREGATE);
224 225 226 227 228
}

static void
gimp_dynamics_output_init (GimpDynamicsOutput *output)
{
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
  GimpDynamicsOutputPrivate *private = GET_PRIVATE (output);

  private->pressure_curve  = gimp_dynamics_output_create_curve (output,
                                                                "pressure-curve");
  private->velocity_curve  = gimp_dynamics_output_create_curve (output,
                                                                "velocity-curve");
  private->direction_curve = gimp_dynamics_output_create_curve (output,
                                                                "direction-curve");
  private->tilt_curve      = gimp_dynamics_output_create_curve (output,
                                                                "tilt-curve");
  private->wheel_curve     = gimp_dynamics_output_create_curve (output,
                                                                "wheel-curve");
  private->random_curve    = gimp_dynamics_output_create_curve (output,
                                                                "random-curve");
  private->fade_curve      = gimp_dynamics_output_create_curve (output,
                                                                "fade-curve");
245 246 247 248 249
}

static void
gimp_dynamics_output_finalize (GObject *object)
{
250
  GimpDynamicsOutputPrivate *private = GET_PRIVATE (object);
251

252 253 254 255 256 257 258
  g_clear_object (&private->pressure_curve);
  g_clear_object (&private->velocity_curve);
  g_clear_object (&private->direction_curve);
  g_clear_object (&private->tilt_curve);
  g_clear_object (&private->wheel_curve);
  g_clear_object (&private->random_curve);
  g_clear_object (&private->fade_curve);
259 260 261 262 263 264 265 266 267 268

  G_OBJECT_CLASS (parent_class)->finalize (object);
}

static void
gimp_dynamics_output_set_property (GObject      *object,
                                   guint         property_id,
                                   const GValue *value,
                                   GParamSpec   *pspec)
{
269
  GimpDynamicsOutputPrivate *private = GET_PRIVATE (object);
270 271 272

  switch (property_id)
    {
273
    case PROP_TYPE:
274
      private->type = g_value_get_enum (value);
275
      break;
276

277
    case PROP_USE_PRESSURE:
278
      private->use_pressure = g_value_get_boolean (value);
279 280
      break;

281
    case PROP_USE_VELOCITY:
282
      private->use_velocity = g_value_get_boolean (value);
283 284
      break;

285
    case PROP_USE_DIRECTION:
286
      private->use_direction = g_value_get_boolean (value);
287 288
      break;

289
    case PROP_USE_TILT:
290
      private->use_tilt = g_value_get_boolean (value);
291 292
      break;

293
    case PROP_USE_WHEEL:
294
      private->use_wheel = g_value_get_boolean (value);
295 296
      break;

297
    case PROP_USE_RANDOM:
298
      private->use_random = g_value_get_boolean (value);
299 300
      break;

301
    case PROP_USE_FADE:
302
      private->use_fade = g_value_get_boolean (value);
303 304
      break;

Alexia Death's avatar
Alexia Death committed
305
    case PROP_PRESSURE_CURVE:
306
      gimp_dynamics_output_copy_curve (g_value_get_object (value),
307
                                       private->pressure_curve);
Alexia Death's avatar
Alexia Death committed
308 309 310
      break;

    case PROP_VELOCITY_CURVE:
311
      gimp_dynamics_output_copy_curve (g_value_get_object (value),
312
                                       private->velocity_curve);
Alexia Death's avatar
Alexia Death committed
313 314 315
      break;

    case PROP_DIRECTION_CURVE:
316
      gimp_dynamics_output_copy_curve (g_value_get_object (value),
317
                                       private->direction_curve);
Alexia Death's avatar
Alexia Death committed
318 319 320
      break;

    case PROP_TILT_CURVE:
321
      gimp_dynamics_output_copy_curve (g_value_get_object (value),
322
                                       private->tilt_curve);
Alexia Death's avatar
Alexia Death committed
323 324
      break;

325 326
    case PROP_WHEEL_CURVE:
      gimp_dynamics_output_copy_curve (g_value_get_object (value),
327
                                       private->wheel_curve);
328 329
      break;

Alexia Death's avatar
Alexia Death committed
330
    case PROP_RANDOM_CURVE:
331
      gimp_dynamics_output_copy_curve (g_value_get_object (value),
332
                                       private->random_curve);
Alexia Death's avatar
Alexia Death committed
333 334 335
      break;

    case PROP_FADE_CURVE:
336
      gimp_dynamics_output_copy_curve (g_value_get_object (value),
337
                                       private->fade_curve);
Alexia Death's avatar
Alexia Death committed
338 339
      break;

340 341 342 343 344 345 346 347 348 349 350 351
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

static void
gimp_dynamics_output_get_property (GObject    *object,
                                   guint       property_id,
                                   GValue     *value,
                                   GParamSpec *pspec)
{
352
  GimpDynamicsOutputPrivate *private = GET_PRIVATE (object);
353 354 355

  switch (property_id)
    {
356
    case PROP_TYPE:
357
      g_value_set_enum (value, private->type);
358
      break;
359

360
    case PROP_USE_PRESSURE:
361
      g_value_set_boolean (value, private->use_pressure);
362 363
      break;

364
    case PROP_USE_VELOCITY:
365
      g_value_set_boolean (value, private->use_velocity);
366 367
      break;

368
    case PROP_USE_DIRECTION:
369
      g_value_set_boolean (value, private->use_direction);
370 371
      break;

372
    case PROP_USE_TILT:
373
      g_value_set_boolean (value, private->use_tilt);
374 375
      break;

376
    case PROP_USE_WHEEL:
377
      g_value_set_boolean (value, private->use_wheel);
378 379
      break;

380
    case PROP_USE_RANDOM:
381
      g_value_set_boolean (value, private->use_random);
382 383
      break;

384
    case PROP_USE_FADE:
385
      g_value_set_boolean (value, private->use_fade);
386 387
      break;

Alexia Death's avatar
Alexia Death committed
388
    case PROP_PRESSURE_CURVE:
389
      g_value_set_object (value, private->pressure_curve);
Alexia Death's avatar
Alexia Death committed
390 391 392
      break;

    case PROP_VELOCITY_CURVE:
393
      g_value_set_object (value, private->velocity_curve);
Alexia Death's avatar
Alexia Death committed
394 395 396
      break;

    case PROP_DIRECTION_CURVE:
397
      g_value_set_object (value, private->direction_curve);
Alexia Death's avatar
Alexia Death committed
398 399 400
      break;

    case PROP_TILT_CURVE:
401
      g_value_set_object (value, private->tilt_curve);
Alexia Death's avatar
Alexia Death committed
402 403
      break;

404
    case PROP_WHEEL_CURVE:
405
      g_value_set_object (value, private->wheel_curve);
406 407
      break;

Alexia Death's avatar
Alexia Death committed
408
    case PROP_RANDOM_CURVE:
409
      g_value_set_object (value, private->random_curve);
Alexia Death's avatar
Alexia Death committed
410 411 412
      break;

    case PROP_FADE_CURVE:
413
      g_value_set_object (value, private->fade_curve);
Alexia Death's avatar
Alexia Death committed
414 415
      break;

416 417 418 419 420 421
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

422 423 424

/*  public functions  */

425
GimpDynamicsOutput *
426 427
gimp_dynamics_output_new (const gchar            *name,
                          GimpDynamicsOutputType  type)
428 429 430 431 432
{
  g_return_val_if_fail (name != NULL, NULL);

  return g_object_new (GIMP_TYPE_DYNAMICS_OUTPUT,
                       "name", name,
433
                       "type", type,
434 435 436
                       NULL);
}

437 438 439
gboolean
gimp_dynamics_output_is_enabled (GimpDynamicsOutput *output)
{
440 441 442 443 444 445 446 447 448
  GimpDynamicsOutputPrivate *private = GET_PRIVATE (output);

  return (private->use_pressure  ||
          private->use_velocity  ||
          private->use_direction ||
          private->use_tilt      ||
          private->use_wheel     ||
          private->use_random    ||
          private->use_fade);
449 450
}

451
gdouble
452
gimp_dynamics_output_get_linear_value (GimpDynamicsOutput *output,
453
                                       const GimpCoords   *coords,
454
                                       GimpPaintOptions   *options,
455
                                       gdouble             fade_point)
456
{
457 458 459 460
  GimpDynamicsOutputPrivate *private = GET_PRIVATE (output);
  gdouble                    total   = 0.0;
  gdouble                    result  = 1.0;
  gint                       factors = 0;
461

462
  if (private->use_pressure)
463
    {
464 465
      total += gimp_curve_map_value (private->pressure_curve,
                                     coords->pressure);
466 467 468
      factors++;
    }

469
  if (private->use_velocity)
470
    {
471
      total += gimp_curve_map_value (private->velocity_curve,
472
                                    (1.0 - coords->velocity));
473 474 475
      factors++;
    }

476
  if (private->use_direction)
477
    {
478
      total += gimp_curve_map_value (private->direction_curve,
479
                                     fmod (coords->direction + 0.5, 1));
480 481 482
      factors++;
    }

483
  if (private->use_tilt)
484
    {
485
      total += gimp_curve_map_value (private->tilt_curve,
486 487
                                     (1.0 - sqrt (SQR (coords->xtilt) +
                                      SQR (coords->ytilt))));
488 489 490
      factors++;
    }

491
  if (private->use_wheel)
492 493
    {
      gdouble wheel;
494 495

      wheel = coords->wheel;
496

497
      total += gimp_curve_map_value (private->wheel_curve, wheel);
498 499 500
      factors++;
    }

501
  if (private->use_random)
502
    {
503
      total += gimp_curve_map_value (private->random_curve,
504
                                     g_random_double_range (0.0, 1.0));
505 506 507
      factors++;
    }

508
  if (private->use_fade)
509
    {
510
      total += gimp_curve_map_value (private->fade_curve, fade_point);
511

512
      factors++;
513 514
    }

515
  if (factors > 0)
516 517
    result = total / factors;

518 519 520 521
#if 0
  g_printerr ("Dynamics queried(linear). Result: %f, factors: %d, total: %f\n",
              result, factors, total);
#endif
522

523 524 525 526
  return result;
}

gdouble
527
gimp_dynamics_output_get_angular_value (GimpDynamicsOutput *output,
528
                                        const GimpCoords   *coords,
529
                                        GimpPaintOptions   *options,
530
                                        gdouble             fade_point)
531
{
532 533
  GimpDynamicsOutputPrivate *private = GET_PRIVATE (output);
  gdouble                    total   = 0.0;
534
  gdouble                    result  = 0.0; /* angles are additive, so we return zero for no change. */
535
  gint                       factors = 0;
536

537
  if (private->use_pressure)
538
    {
539 540
      total += gimp_curve_map_value (private->pressure_curve,
                                     coords->pressure);
541 542 543
      factors++;
    }

544
  if (private->use_velocity)
545
    {
546
      total += gimp_curve_map_value (private->velocity_curve,
547
                                    (1.0 - coords->velocity));
548 549 550
      factors++;
    }

551
  if (private->use_direction)
552
    {
553 554 555 556 557 558 559 560 561 562 563 564 565
      gdouble angle = gimp_curve_map_value (private->direction_curve,
                                            coords->direction);

      if (options->brush_lock_to_view)
        {
          if (coords->reflect)
            angle = 0.5 - angle;

          angle -= coords->angle;
          angle  = fmod (fmod (angle, 1.0) + 1.0, 1.0);
        }

      total += angle;
566 567
      factors++;
    }
568 569 570 571

  /* For tilt to make sense, it needs to be converted to an angle, not
   * just a vector
   */
572
  if (private->use_tilt)
573
    {
574 575
      gdouble tilt_x = coords->xtilt;
      gdouble tilt_y = coords->ytilt;
576
      gdouble tilt   = 0.0;
577 578 579

      if (tilt_x == 0.0)
        {
580
          if (tilt_y > 0.0)
581
            tilt = 0.25;
582
          else if (tilt_y < 0.0)
583
            tilt = 0.75;
584
          else
585
            tilt = 0.0;
586 587 588 589 590 591
        }
      else
        {
          tilt = atan ((- 1.0 * tilt_y) /
                                tilt_x) / (2 * G_PI);

592 593 594
          if (tilt_x > 0.0)
            tilt = tilt + 0.5;
        }
595 596 597 598 599 600 601 602

      tilt = tilt + 0.5; /* correct the angle, its wrong by 180 degrees */

      while (tilt > 1.0)
        tilt -= 1.0;

      while (tilt < 0.0)
        tilt += 1.0;
603

604
      total += gimp_curve_map_value (private->tilt_curve, tilt);
605 606 607
      factors++;
    }

608
  if (private->use_wheel)
609 610 611
    {
      gdouble angle = 1.0 - fmod(0.5 + coords->wheel, 1);

612
      total += gimp_curve_map_value (private->wheel_curve, angle);
613 614 615
      factors++;
    }

616
  if (private->use_random)
617
    {
618
      total += gimp_curve_map_value (private->random_curve,
619
                                     g_random_double_range (0.0, 1.0));
620 621 622
      factors++;
    }

623
  if (private->use_fade)
624
    {
625
      total += gimp_curve_map_value (private->fade_curve, fade_point);
626

627
      factors++;
628 629
    }

630
  if (factors > 0)
631 632
    result = total / factors;

633 634 635 636 637
#if 0
  g_printerr ("Dynamics queried(angle). Result: %f, factors: %d, total: %f\n",
              result, factors, total);
#endif

638
   return result;
639 640 641
}

gdouble
642
gimp_dynamics_output_get_aspect_value (GimpDynamicsOutput *output,
643
                                       const GimpCoords   *coords,
644
                                       GimpPaintOptions   *options,
645
                                       gdouble             fade_point)
646
{
647 648 649 650 651
  GimpDynamicsOutputPrivate *private = GET_PRIVATE (output);
  gdouble                    total   = 0.0;
  gint                       factors = 0;
  gdouble                    sign    = 1.0;
  gdouble                    result  = 1.0;
652

653
  if (private->use_pressure)
654
    {
655 656
      total += gimp_curve_map_value (private->pressure_curve,
                                     coords->pressure);
657 658 659
      factors++;
    }

660
  if (private->use_velocity)
661
    {
662 663
      total += gimp_curve_map_value (private->velocity_curve,
                                     coords->velocity);
664 665 666
      factors++;
    }

667
  if (private->use_direction)
668
    {
669 670
      gdouble direction = gimp_curve_map_value (private->direction_curve,
                                                coords->direction);
671

672 673
      if (((direction > 0.875) && (direction <= 1.0)) ||
          ((direction > 0.0) && (direction < 0.125))  ||
674 675
          ((direction > 0.375) && (direction < 0.625)))
        sign = -1.0;
676

677
      total += 1.0;
678 679 680
      factors++;
    }

681
  if (private->use_tilt)
682
    {
683
      gdouble tilt_value =  MAX (fabs (coords->xtilt), fabs (coords->ytilt));
684

685
      tilt_value = gimp_curve_map_value (private->tilt_curve,
686 687
                                         tilt_value);

688 689
      total += tilt_value;

690 691 692
      factors++;
    }

693
  if (private->use_wheel)
694
    {
695 696
      gdouble wheel = gimp_curve_map_value (private->wheel_curve,
                                            coords->wheel);
697

698 699
      if (((wheel > 0.875) && (wheel <= 1.0)) ||
          ((wheel > 0.0) && (wheel < 0.125))  ||
700 701 702 703
          ((wheel > 0.375) && (wheel < 0.625)))
        sign = -1.0;

      total += 1.0;
704
      factors++;
705

706 707
    }

708
  if (private->use_random)
709
    {
710
      gdouble random = gimp_curve_map_value (private->random_curve,
711
                                             g_random_double_range (0.0, 1.0));
712

713
      total += random;
714 715 716
      factors++;
    }

717
  if (private->use_fade)
718
    {
719
      total += gimp_curve_map_value (private->fade_curve, fade_point);
720

721
      factors++;
722 723
    }

724
  if (factors > 0)
725 726
    result = total / factors;

727

728
#if 0
729 730
  g_printerr ("Dynamics queried(aspect). Result: %f, factors: %d, total: %f sign: %f\n",
              result, factors, total, sign);
731
#endif
732
  result = CLAMP (result * sign, -1.0, 1.0);
733

734
  return result;
735
}
736 737

static void
738 739
gimp_dynamics_output_copy_curve (GimpCurve *src,
                                 GimpCurve *dest)
740
{
741
  if (src && dest)
742 743 744 745 746 747
    {
      gimp_config_copy (GIMP_CONFIG (src),
                        GIMP_CONFIG (dest),
                        GIMP_CONFIG_PARAM_SERIALIZE);
    }
}
748

749 750 751 752 753 754 755 756 757 758 759 760 761
static GimpCurve *
gimp_dynamics_output_create_curve (GimpDynamicsOutput *output,
                                   const gchar        *name)
{
  GimpCurve *curve = GIMP_CURVE (gimp_curve_new (name));

  g_signal_connect_object (curve, "dirty",
                           G_CALLBACK (gimp_dynamics_output_curve_dirty),
                           output, 0);

  return curve;
}

762
static void
763 764
gimp_dynamics_output_curve_dirty (GimpCurve          *curve,
                                  GimpDynamicsOutput *output)
765
{
766
  g_object_notify (G_OBJECT (output), gimp_object_get_name (curve));
767
}