1 // Aseprite Document Library
2 // Copyright (c) 2001-2016 David Capello
3 //
4 // This file is released under the terms of the MIT license.
5 // Read LICENSE.txt for more information.
6 
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10 
11 #include "doc/brush.h"
12 
13 #include "base/pi.h"
14 #include "doc/algo.h"
15 #include "doc/algorithm/polygon.h"
16 #include "doc/blend_internals.h"
17 #include "doc/image.h"
18 #include "doc/image_impl.h"
19 #include "doc/primitives.h"
20 
21 #include <cmath>
22 
23 namespace doc {
24 
25 static int generation = 0;
26 
Brush()27 Brush::Brush()
28 {
29   m_type = kCircleBrushType;
30   m_size = 1;
31   m_angle = 0;
32   m_pattern = BrushPattern::DEFAULT;
33   m_gen = 0;
34 
35   regenerate();
36 }
37 
Brush(BrushType type,int size,int angle)38 Brush::Brush(BrushType type, int size, int angle)
39 {
40   m_type = type;
41   m_size = size;
42   m_angle = angle;
43   m_pattern = BrushPattern::DEFAULT;
44   m_gen = 0;
45 
46   regenerate();
47 }
48 
Brush(const Brush & brush)49 Brush::Brush(const Brush& brush)
50 {
51   m_type = brush.m_type;
52   m_size = brush.m_size;
53   m_angle = brush.m_angle;
54   m_image = brush.m_image;
55   m_maskBitmap = brush.m_maskBitmap;
56   m_pattern = brush.m_pattern;
57   m_patternOrigin = brush.m_patternOrigin;
58   m_gen = 0;
59 
60   regenerate();
61 }
62 
~Brush()63 Brush::~Brush()
64 {
65   clean();
66 }
67 
setType(BrushType type)68 void Brush::setType(BrushType type)
69 {
70   m_type = type;
71   if (m_type != kImageBrushType)
72     regenerate();
73   else
74     clean();
75 }
76 
setSize(int size)77 void Brush::setSize(int size)
78 {
79   m_size = size;
80   regenerate();
81 }
82 
setAngle(int angle)83 void Brush::setAngle(int angle)
84 {
85   m_angle = angle;
86   regenerate();
87 }
88 
setImage(const Image * image,const Image * maskBitmap)89 void Brush::setImage(const Image* image,
90                      const Image* maskBitmap)
91 {
92   m_type = kImageBrushType;
93   m_image.reset(Image::createCopy(image));
94   if (maskBitmap)
95     m_maskBitmap.reset(Image::createCopy(maskBitmap));
96   else {
97     int w = image->width();
98     int h = image->height();
99     m_maskBitmap.reset(Image::create(IMAGE_BITMAP, w, h));
100     LockImageBits<BitmapTraits> bits(m_maskBitmap.get());
101     auto pos = bits.begin();
102     for (int v=0; v<h; ++v)
103       for (int u=0; u<w; ++u, ++pos)
104         *pos = (get_pixel(image, u, v) != image->maskColor());
105   }
106 
107   m_backupImage.reset();
108   m_mainColor.reset();
109   m_bgColor.reset();
110 
111   resetBounds();
112 }
113 
114 template<class ImageTraits,
115          color_t color_mask,
116          color_t alpha_mask,
117          color_t alpha_shift>
replace_image_colors(Image * image,Image * maskBitmap,const bool useMain,color_t mainColor,const bool useBg,color_t bgColor)118 static void replace_image_colors(
119   Image* image,
120   Image* maskBitmap,
121   const bool useMain, color_t mainColor,
122   const bool useBg, color_t bgColor)
123 {
124   LockImageBits<ImageTraits> bits(image, Image::ReadWriteLock);
125   const LockImageBits<BitmapTraits> maskBits(maskBitmap);
126   bool hasAlpha = false; // True if "image" has a pixel with alpha < 255
127   color_t srcMainColor, srcBgColor;
128   srcMainColor = srcBgColor = 0;
129 
130   auto mask_it = maskBits.begin();
131   for (const auto& pixel : bits) {
132     if (!*mask_it)
133       continue;
134 
135     if ((pixel & alpha_mask) != alpha_mask) {  // If alpha != 255
136       hasAlpha = true;
137     }
138     else if (srcBgColor == 0) {
139       srcMainColor = srcBgColor = pixel;
140     }
141     else if (pixel != srcBgColor && srcMainColor == srcBgColor) {
142       srcMainColor = pixel;
143     }
144 
145     ++mask_it;
146   }
147 
148   int t;
149   if (hasAlpha) {
150     if (useMain || useBg) {
151       const color_t color = (useMain ? mainColor: useBg);
152       for (auto& pixel : bits) {
153         color_t a1 = (pixel & alpha_mask) >> alpha_shift;
154         const color_t a2 = (color & alpha_mask) >> alpha_shift;
155         a1 = MUL_UN8(a1, a2, t);
156         pixel =
157           (a1 << alpha_shift) |
158           (color & color_mask);
159       }
160     }
161   }
162   else {
163     for (auto& pixel : bits) {
164       color_t color;
165       if (useMain && ((pixel != srcBgColor) || (srcMainColor == srcBgColor)))
166         color = mainColor;
167       else if (useBg && (pixel == srcBgColor))
168         color = bgColor;
169       else
170         continue;
171 
172       color_t a1 = (pixel & alpha_mask) >> alpha_shift;
173       color_t a2 = (color & alpha_mask) >> alpha_shift;
174       a1 = MUL_UN8(a1, a2, t);
175       pixel =
176         (a1 << alpha_shift) |
177         (color & color_mask);
178     }
179   }
180 }
181 
replace_image_colors_indexed(Image * image,Image * maskBitmap,const bool useMain,const color_t mainColor,const bool useBg,const color_t bgColor)182 static void replace_image_colors_indexed(
183   Image* image,
184   Image* maskBitmap,
185   const bool useMain, const color_t mainColor,
186   const bool useBg, const color_t bgColor)
187 {
188   LockImageBits<IndexedTraits> bits(image, Image::ReadWriteLock);
189   const LockImageBits<BitmapTraits> maskBits(maskBitmap);
190   bool hasAlpha = false; // True if "image" has a pixel with the mask color
191   color_t maskColor = image->maskColor();
192   color_t srcMainColor, srcBgColor;
193   srcMainColor = srcBgColor = maskColor;
194 
195   auto mask_it = maskBits.begin();
196   for (const auto& pixel : bits) {
197     if (!*mask_it)
198       continue;
199 
200     if (pixel == maskColor) {
201       hasAlpha = true;
202     }
203     else if (srcBgColor == maskColor) {
204       srcMainColor = srcBgColor = pixel;
205     }
206     else if (pixel != srcBgColor && srcMainColor == srcBgColor) {
207       srcMainColor = pixel;
208     }
209 
210     ++mask_it;
211   }
212 
213   if (hasAlpha) {
214     for (auto& pixel : bits) {
215       if (pixel != maskColor) {
216         if (useMain)
217           pixel = mainColor;
218         else if (useBg)
219           pixel = bgColor;
220       }
221     }
222   }
223   else {
224     for (auto& pixel : bits) {
225       if (useMain && ((pixel != srcBgColor) || (srcMainColor == srcBgColor))) {
226         pixel = mainColor;
227       }
228       else if (useBg && (pixel == srcBgColor)) {
229         pixel = bgColor;
230       }
231     }
232   }
233 }
234 
setImageColor(ImageColor imageColor,color_t color)235 void Brush::setImageColor(ImageColor imageColor, color_t color)
236 {
237   ASSERT(m_image);
238   if (!m_image)
239     return;
240 
241   if (!m_backupImage)
242     m_backupImage.reset(Image::createCopy(m_image.get()));
243   else
244     m_image.reset(Image::createCopy(m_backupImage.get()));
245 
246   ASSERT(m_maskBitmap);
247 
248   switch (imageColor) {
249     case ImageColor::MainColor:
250       m_mainColor.reset(new color_t(color));
251       break;
252     case ImageColor::BackgroundColor:
253       m_bgColor.reset(new color_t(color));
254       break;
255   }
256 
257   switch (m_image->pixelFormat()) {
258 
259     case IMAGE_RGB:
260       replace_image_colors<RgbTraits, rgba_rgb_mask, rgba_a_mask, rgba_a_shift>(
261         m_image.get(), m_maskBitmap.get(),
262         (m_mainColor ? true: false), (m_mainColor ? *m_mainColor: 0),
263         (m_bgColor ? true: false), (m_bgColor ? *m_bgColor: 0));
264       break;
265 
266     case IMAGE_GRAYSCALE:
267       replace_image_colors<GrayscaleTraits, graya_v_mask, graya_a_mask, graya_a_shift>(
268         m_image.get(), m_maskBitmap.get(),
269         (m_mainColor ? true: false), (m_mainColor ? *m_mainColor: 0),
270         (m_bgColor ? true: false), (m_bgColor ? *m_bgColor: 0));
271       break;
272 
273     case IMAGE_INDEXED:
274       replace_image_colors_indexed(
275         m_image.get(), m_maskBitmap.get(),
276         (m_mainColor ? true: false), (m_mainColor ? *m_mainColor: 0),
277         (m_bgColor ? true: false), (m_bgColor ? *m_bgColor: 0));
278       break;
279   }
280 }
281 
282 // Cleans the brush's data (image and region).
clean()283 void Brush::clean()
284 {
285   m_gen = ++generation;
286   m_image.reset();
287   m_maskBitmap.reset();
288   m_backupImage.reset();
289 }
290 
algo_hline(int x1,int y,int x2,void * data)291 static void algo_hline(int x1, int y, int x2, void *data)
292 {
293   draw_hline(reinterpret_cast<Image*>(data), x1, y, x2, BitmapTraits::max_value);
294 }
295 
296 // Regenerates the brush bitmap and its rectangle's region.
regenerate()297 void Brush::regenerate()
298 {
299   clean();
300 
301   ASSERT(m_size > 0);
302 
303   int size = m_size;
304   if (m_type == kSquareBrushType && m_angle != 0 && m_size > 2)
305     size = (int)std::sqrt((double)2*m_size*m_size)+2;
306 
307   m_image.reset(Image::create(IMAGE_BITMAP, size, size));
308   m_maskBitmap.reset();
309 
310   if (size == 1) {
311     clear_image(m_image.get(), BitmapTraits::max_value);
312   }
313   else {
314     clear_image(m_image.get(), BitmapTraits::min_value);
315 
316     switch (m_type) {
317 
318       case kCircleBrushType:
319         fill_ellipse(m_image.get(), 0, 0, size-1, size-1, BitmapTraits::max_value);
320         break;
321 
322       case kSquareBrushType:
323         if (m_angle == 0 || size <= 2) {
324           clear_image(m_image.get(), BitmapTraits::max_value);
325         }
326         else {
327           double a = PI * m_angle / 180;
328           int c = size/2;
329           int r = m_size/2;
330           int d = m_size;
331           int x1 = int(c + r*cos(a-PI/2) + r*cos(a-PI));
332           int y1 = int(c - r*sin(a-PI/2) - r*sin(a-PI));
333           int x2 = int(x1 + d*cos(a));
334           int y2 = int(y1 - d*sin(a));
335           int x3 = int(x2 + d*cos(a+PI/2));
336           int y3 = int(y2 - d*sin(a+PI/2));
337           int x4 = int(x3 + d*cos(a+PI));
338           int y4 = int(y3 - d*sin(a+PI));
339           int points[8] = { x1, y1, x2, y2, x3, y3, x4, y4 };
340 
341           doc::algorithm::polygon(4, points, m_image.get(), algo_hline);
342         }
343         break;
344 
345       case kLineBrushType: {
346         double a = PI * m_angle / 180;
347         double r = m_size/2;
348         double d = m_size;
349         int x1 = int(r + r*cos(a+PI));
350         int y1 = int(r - r*sin(a+PI));
351         int x2 = int(x1 + d*cos(a));
352         int y2 = int(y1 - d*sin(a));
353 
354         draw_line(m_image.get(), x1, y1, x2, y2, BitmapTraits::max_value);
355         break;
356       }
357     }
358   }
359 
360   resetBounds();
361 }
362 
resetBounds()363 void Brush::resetBounds()
364 {
365   m_center = gfx::Point(m_image->width()/2,
366                         m_image->height()/2);
367   m_bounds = gfx::Rect(-m_center,
368                        gfx::Size(m_image->width(),
369                                  m_image->height()));
370 }
371 
372 } // namespace doc
373