synfig-studio  1.0.3
brushlib.h
Go to the documentation of this file.
1 /* === S Y N F I G ========================================================= */
21 /* ========================================================================= */
22 
23 /* === S T A R T =========================================================== */
24 
25 #ifndef __SYNFIG_BRUSH_H
26 #define __SYNFIG_BRUSH_H
27 
28 /* === H E A D E R S ======================================================= */
29 
30 #include <synfig/surface.h>
31 #include <ETL/angle> // we need PI
32 #include "brushlib/brushlib.hpp"
33 
34 /* === M A C R O S ========================================================= */
35 
36 /* === T Y P E D E F S ===================================================== */
37 
38 /* === C L A S S E S & S T R U C T S ======================================= */
39 
40 namespace brushlib {
41  class ActiveSurface: public Surface {
42  public:
43  virtual bool draw_dab(
44  float /* x */, float /* y */,
45  float /* radius */,
46  float /* color_r */, float /* color_g */, float /* color_b */,
47  float /* opaque */, float /* hardness */ = 0.5,
48  float /* alpha_eraser */ = 1.0,
49  float /* aspect_ratio */ = 1.0, float /* angle */ = 0.0,
50  float /* lock_alpha */ = 0.0
51  ) { return false; };
52 
53  virtual void get_color(
54  float /* x */, float /* y */,
55  float /* radius */,
56  float * color_r, float * color_g, float * color_b, float * color_a
57  ) { *color_r = 0.f; *color_g = 0.f; *color_b = 0.f; *color_a = 0.f; };
58  };
59 
60  class SurfaceWrapper: public ActiveSurface {
61  public:
62  typedef synfig::Surface surface_type;
66  int extra_top;
68  int offset_x;
69  int offset_y;
70 
71  explicit SurfaceWrapper(surface_type *surface = NULL):
73  extra_left(0), extra_right(0),
74  extra_top(0), extra_bottom(0),
75  offset_x(0), offset_y(0) { }
76 
77  void reset() {
78  extra_left = 0;
79  extra_right = 0;
80  extra_top = 0;
81  extra_bottom = 0;
82  offset_x = 0;
83  offset_y = 0;
84  }
85 
86  virtual bool draw_dab(
87  float x, float y,
88  float radius,
89  float color_r, float color_g, float color_b,
90  float opaque, float hardness = 0.5,
91  float alpha_eraser = 1.0,
92  float aspect_ratio = 1.0, float angle = 0.0,
93  float /* lock_alpha */ = 0.0
94  ) {
95  if (surface == NULL) return false;
96 
97  x += (float)offset_x;
98  y += (float)offset_y;
99 
100  float cs = cosf(angle/180.f*(float)PI);
101  float sn = sinf(angle/180.f*(float)PI);
102 
103  // calculate bounds
104  if (aspect_ratio < 1.0) aspect_ratio = 1.0;
105  if (hardness > 1.0) hardness = 1.0;
106  if (hardness < 0.0) hardness = 0.0;
107  float maxr = fabsf(radius);
108  int x0 = (int)(x - maxr - 1.f);
109  int x1 = (int)(x + maxr + 1.f);
110  int y0 = (int)(y - maxr - 1.f);
111  int y1 = (int)(y + maxr + 1.f);
112 
113  if (x0 < 0
114  || y0 < 0
115  || x1+1 > surface->get_w()
116  || y1+1 > surface->get_h() )
117  {
118  int l = x0 < 0 ? x0 : 0;
119  int t = y0 < 0 ? y0 : 0;
120  int r = x1+1 > surface->get_w() ? x1+1 : surface->get_w();
121  int b = y1+1 > surface->get_h() ? y1+1 : surface->get_h();
122 
123  extra_left -= l; // increase because l and t is negative
124  extra_top -= t;
125  extra_right += r - surface->get_w();
126  extra_bottom += b - surface->get_h();
127 
128  synfig::Surface tmp;
129  tmp = *surface;
130  surface->set_wh(r-l, b-t);
131  surface->clear();
132  synfig::Surface::pen p(surface->get_pen(-l, -t));
133  tmp.blit_to(p);
134 
135  offset_x -= l;
136  offset_y -= t;
137  x -= (float)l; y -= (float)t;
138  x0 -= l; y0 -= t;
139  x1 -= l; y1 -= t;
140  }
141 
142  bool erase = alpha_eraser < 1.0;
143  for(int py = y0; py <= y1; py++)
144  {
145  for(int px = x0; px <= x1; px++)
146  {
147  float dx = (float)px - x;
148  float dy = (float)py - y;
149  float dyr = (dy*cs-dx*sn)*aspect_ratio;
150  float dxr = (dy*sn+dx*cs);
151  float dd = (dyr*dyr + dxr*dxr) / (radius*radius);
152  if (dd <= 1.f)
153  {
154  float opa = dd < hardness
155  ? dd + 1-(dd/hardness)
156  : hardness/(1-hardness)*(1-dd);
157  opa *= opaque;
158  synfig::Color &c = (*surface)[py][px];
159  if (erase)
160  {
161  c.set_a(c.get_a()*(1.0 - (1.0 - alpha_eraser)*opa));
162  }
163  else
164  {
165  float sum_alpha = opa + c.get_a();
166  if (sum_alpha > 1.0) sum_alpha = 1.0;
167  float inv_opa = sum_alpha - opa;
168  c.set_r(c.get_r()*inv_opa + color_r*opa);
169  c.set_g(c.get_g()*inv_opa + color_g*opa);
170  c.set_b(c.get_b()*inv_opa + color_b*opa);
171  c.set_a(sum_alpha);
172  }
173  }
174  }
175  }
176 
177  return true;
178  };
179 
180  virtual void get_color(
181  float x, float y,
182  float /* radius */,
183  float * color_r, float * color_g, float * color_b, float * color_a
184  ) {
185  if (surface == NULL) {
186  *color_r = 0.f; *color_g = 0.f; *color_b = 0.f; *color_a = 0.f;
187  return;
188  }
189 
190  x += (float)offset_x;
191  y += (float)offset_y;
192 
193  synfig::Color c = surface->cubic_sample(x, y);
194  *color_r = c.get_r();
195  *color_g = c.get_g();
196  *color_b = c.get_b();
197  *color_a = c.get_a();
198  };
199  };
200 
201 }; // END of namespace brush
202 
203 /* === E N D =============================================================== */
204 
205 #endif