Blame synfig-studio/src/brushlib/mapping.hpp

4a0d4f
/* brushlib - The MyPaint Brush Library
4a0d4f
 * Copyright (C) 2007-2008 Martin Renold <martinxyz@gmx.ch></martinxyz@gmx.ch>
4a0d4f
 *
4a0d4f
 * Permission to use, copy, modify, and/or distribute this software for any
4a0d4f
 * purpose with or without fee is hereby granted, provided that the above
4a0d4f
 * copyright notice and this permission notice appear in all copies.
4a0d4f
 *
4a0d4f
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
4a0d4f
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
4a0d4f
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
4a0d4f
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
4a0d4f
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
4a0d4f
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
4a0d4f
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
4a0d4f
 */
4a0d4f
4a0d4f
#ifndef __MAPPING_H__
4a0d4f
#define __MAPPING_H__
4a0d4f
4a0d4f
// user-defined mappings
4a0d4f
// (the curves you can edit in the brush settings)
4a0d4f
f5e87b
namespace brushlib {
4a0d4f
4a0d4f
class Mapping {
4a0d4f
private:
4a0d4f
  typedef struct {
4a0d4f
    // a set of control points (stepwise linear)
4a0d4f
    float xvalues[8];
4a0d4f
    float yvalues[8];
4a0d4f
    int n;
4a0d4f
  } ControlPoints;
4a0d4f
4a0d4f
  int inputs;
4a0d4f
  ControlPoints * pointsList; // one for each input
4a0d4f
  int inputs_used; // optimization
4a0d4f
public:
4a0d4f
  float base_value;
4a0d4f
4a0d4f
  Mapping(int inputs_) {
4a0d4f
    inputs = inputs_;
4a0d4f
    pointsList = new ControlPoints[inputs];
4a0d4f
    for (int i=0; i
4a0d4f
    inputs_used = 0;
4a0d4f
    base_value = 0;
4a0d4f
  }
4a0d4f
  ~Mapping() {
cfd415
    delete [] pointsList;
4a0d4f
  }
4a0d4f
4a0d4f
  void set_n (int input, int n)
4a0d4f
  {
4a0d4f
    assert (input >= 0 && input < inputs);
4a0d4f
    assert (n >= 0 && n <= 8);
4a0d4f
    assert (n != 1); // cannot build a linear mapping with only one point
4a0d4f
    ControlPoints * p = pointsList + input;
4a0d4f
4a0d4f
    if (n != 0 && p->n == 0) inputs_used++;
4a0d4f
    if (n == 0 && p->n != 0) inputs_used--;
4a0d4f
    assert(inputs_used >= 0);
4a0d4f
    assert(inputs_used <= inputs);
4a0d4f
4a0d4f
    p->n = n;
4a0d4f
  }
4a0d4f
4a0d4f
  void set_point (int input, int index, float x, float y)
4a0d4f
  {
4a0d4f
    assert (input >= 0 && input < inputs);
4a0d4f
    assert (index >= 0 && index < 8);
4a0d4f
    ControlPoints * p = pointsList + input;
4a0d4f
    assert (index < p->n);
4a0d4f
4a0d4f
    if (index > 0) {
4a0d4f
      assert (x >= p->xvalues[index-1]);
4a0d4f
    }
4a0d4f
4a0d4f
    p->xvalues[index] = x;
4a0d4f
    p->yvalues[index] = y;
4a0d4f
  }
4a0d4f
4a0d4f
  bool is_constant()
4a0d4f
  {
4a0d4f
    return inputs_used == 0;
4a0d4f
  }
4a0d4f
4a0d4f
  float calculate (float * data)
4a0d4f
  {
4a0d4f
    int j;
4a0d4f
    float result;
4a0d4f
    result = base_value;
4a0d4f
4a0d4f
    // constant mapping (common case)
4a0d4f
    if (inputs_used == 0) return result;
4a0d4f
4a0d4f
    for (j=0; j
4a0d4f
      ControlPoints * p = pointsList + j;
4a0d4f
4a0d4f
      if (p->n) {
4a0d4f
        float x, y;
4a0d4f
        x = data[j];
4a0d4f
4a0d4f
        // find the segment with the slope that we need to use
4a0d4f
        float x0, y0, x1, y1;
4a0d4f
        x0 = p->xvalues[0];
4a0d4f
        y0 = p->yvalues[0];
4a0d4f
        x1 = p->xvalues[1];
4a0d4f
        y1 = p->yvalues[1];
4a0d4f
4a0d4f
        int i;
4a0d4f
        for (i=2; i<p->n && x>x1; i++) {</p->
4a0d4f
          x0 = x1;
4a0d4f
          y0 = y1;
4a0d4f
          x1 = p->xvalues[i];
4a0d4f
          y1 = p->yvalues[i];
4a0d4f
        }
4a0d4f
4a0d4f
        if (x0 == x1) {
4a0d4f
          y = y0;
4a0d4f
        } else {
4a0d4f
          // linear interpolation
4a0d4f
          y = (y1*(x - x0) + y0*(x1 - x)) / (x1 - x0);
4a0d4f
        }
4a0d4f
4a0d4f
        result += y;
4a0d4f
      }
4a0d4f
    }
4a0d4f
    return result;
4a0d4f
  }
4a0d4f
4a0d4f
  // used in python for the global pressure mapping
4a0d4f
  float calculate_single_input (float input)
4a0d4f
  {
4a0d4f
    assert(inputs == 1);
4a0d4f
    return calculate(&input);
4a0d4f
  }
4a0d4f
};
4a0d4f
4a0d4f
}
4a0d4f
4a0d4f
#endif