synfig-studio  1.0.3
mapping.hpp
Go to the documentation of this file.
1 /* brushlib - The MyPaint Brush Library
2  * Copyright (C) 2007-2008 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 #ifndef __MAPPING_H__
18 #define __MAPPING_H__
19 
20 // user-defined mappings
21 // (the curves you can edit in the brush settings)
22 
23 namespace brushlib {
24 
25 class Mapping {
26 private:
27  typedef struct {
28  // a set of control points (stepwise linear)
29  float xvalues[8];
30  float yvalues[8];
31  int n;
32  } ControlPoints;
33 
34  int inputs;
35  ControlPoints * pointsList; // one for each input
36  int inputs_used; // optimization
37 public:
38  float base_value;
39 
40  Mapping(int inputs_) {
41  inputs = inputs_;
42  pointsList = new ControlPoints[inputs];
43  for (int i=0; i<inputs; i++) pointsList[i].n = 0;
44  inputs_used = 0;
45  base_value = 0;
46  }
48  delete pointsList;
49  }
50 
51  void set_n (int input, int n)
52  {
53  assert (input >= 0 && input < inputs);
54  assert (n >= 0 && n <= 8);
55  assert (n != 1); // cannot build a linear mapping with only one point
56  ControlPoints * p = pointsList + input;
57 
58  if (n != 0 && p->n == 0) inputs_used++;
59  if (n == 0 && p->n != 0) inputs_used--;
60  assert(inputs_used >= 0);
61  assert(inputs_used <= inputs);
62 
63  p->n = n;
64  }
65 
66  void set_point (int input, int index, float x, float y)
67  {
68  assert (input >= 0 && input < inputs);
69  assert (index >= 0 && index < 8);
70  ControlPoints * p = pointsList + input;
71  assert (index < p->n);
72 
73  if (index > 0) {
74  assert (x >= p->xvalues[index-1]);
75  }
76 
77  p->xvalues[index] = x;
78  p->yvalues[index] = y;
79  }
80 
81  bool is_constant()
82  {
83  return inputs_used == 0;
84  }
85 
86  float calculate (float * data)
87  {
88  int j;
89  float result;
90  result = base_value;
91 
92  // constant mapping (common case)
93  if (inputs_used == 0) return result;
94 
95  for (j=0; j<inputs; j++) {
96  ControlPoints * p = pointsList + j;
97 
98  if (p->n) {
99  float x, y;
100  x = data[j];
101 
102  // find the segment with the slope that we need to use
103  float x0, y0, x1, y1;
104  x0 = p->xvalues[0];
105  y0 = p->yvalues[0];
106  x1 = p->xvalues[1];
107  y1 = p->yvalues[1];
108 
109  int i;
110  for (i=2; i<p->n && x>x1; i++) {
111  x0 = x1;
112  y0 = y1;
113  x1 = p->xvalues[i];
114  y1 = p->yvalues[i];
115  }
116 
117  if (x0 == x1) {
118  y = y0;
119  } else {
120  // linear interpolation
121  y = (y1*(x - x0) + y0*(x1 - x)) / (x1 - x0);
122  }
123 
124  result += y;
125  }
126  }
127  return result;
128  }
129 
130  // used in python for the global pressure mapping
131  float calculate_single_input (float input)
132  {
133  assert(inputs == 1);
134  return calculate(&input);
135  }
136 };
137 
138 }
139 
140 #endif