source: synfigstudio/trunk/fuentes/src/brushlib.h @ 481

Last change on this file since 481 was 481, checked in by jrpelegrina, 4 years ago

First release to xenial

File size: 5.5 KB
Line 
1/* === S Y N F I G ========================================================= */
2/*!     \file brushlib.h
3**      \brief Helper file to integrte brushlib into synfig
4**
5**      $Id$
6**
7**      \legal
8**      ......... ... 2014 Ivan Mahonin
9**
10**      This package is free software; you can redistribute it and/or
11**      modify it under the terms of the GNU General Public License as
12**      published by the Free Software Foundation; either version 2 of
13**      the License, or (at your option) any later version.
14**
15**      This package is distributed in the hope that it will be useful,
16**      but WITHOUT ANY WARRANTY; without even the implied warranty of
17**      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18**      General Public License for more details.
19**      \endlegal
20*/
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
40namespace 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;
63                surface_type *surface;
64                int extra_left;
65                int extra_right;
66                int extra_top;
67                int extra_bottom;
68                int offset_x;
69                int offset_y;
70
71                explicit SurfaceWrapper(surface_type *surface = NULL):
72                        surface(surface),
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
Note: See TracBrowser for help on using the repository browser.