1 | // Aseprite |
2 | // Copyright (C) 2021 Igara Studio S.A. |
3 | // |
4 | // This program is distributed under the terms of |
5 | // the End-User License Agreement for Aseprite. |
6 | |
7 | #ifdef HAVE_CONFIG_H |
8 | #include "config.h" |
9 | #endif |
10 | |
11 | #include "app/tools/symmetry.h" |
12 | |
13 | #include "app/tools/point_shape.h" |
14 | #include "app/tools/tool_loop.h" |
15 | |
16 | namespace app { |
17 | namespace tools { |
18 | |
19 | void Symmetry::generateStrokes(const Stroke& stroke, Strokes& strokes, |
20 | ToolLoop* loop) |
21 | { |
22 | Stroke stroke2; |
23 | strokes.push_back(stroke); |
24 | gen::SymmetryMode symmetryMode = loop->getSymmetry()->mode(); |
25 | switch (symmetryMode) { |
26 | case gen::SymmetryMode::NONE: |
27 | ASSERT(false); |
28 | break; |
29 | |
30 | case gen::SymmetryMode::HORIZONTAL: |
31 | case gen::SymmetryMode::VERTICAL: |
32 | calculateSymmetricalStroke(stroke, stroke2, loop, symmetryMode); |
33 | strokes.push_back(stroke2); |
34 | break; |
35 | |
36 | case gen::SymmetryMode::BOTH: { |
37 | calculateSymmetricalStroke(stroke, stroke2, loop, gen::SymmetryMode::HORIZONTAL); |
38 | strokes.push_back(stroke2); |
39 | |
40 | Stroke stroke3; |
41 | calculateSymmetricalStroke(stroke, stroke3, loop, gen::SymmetryMode::VERTICAL); |
42 | strokes.push_back(stroke3); |
43 | |
44 | Stroke stroke4; |
45 | calculateSymmetricalStroke(stroke3, stroke4, loop, gen::SymmetryMode::BOTH); |
46 | strokes.push_back(stroke4); |
47 | break; |
48 | } |
49 | } |
50 | } |
51 | |
52 | void Symmetry::calculateSymmetricalStroke(const Stroke& refStroke, Stroke& stroke, |
53 | ToolLoop* loop, gen::SymmetryMode symmetryMode) |
54 | { |
55 | int brushSize, brushCenter; |
56 | if (loop->getPointShape()->isFloodFill()) { |
57 | brushSize = 1; |
58 | brushCenter = 0; |
59 | } |
60 | else { |
61 | // TODO we should flip the brush center+image+bitmap or just do |
62 | // the symmetry of all pixels |
63 | auto brush = loop->getBrush(); |
64 | if (symmetryMode == gen::SymmetryMode::HORIZONTAL || symmetryMode == gen::SymmetryMode::BOTH) { |
65 | brushSize = brush->bounds().w; |
66 | brushCenter = brush->center().x; |
67 | } |
68 | else { |
69 | brushSize = brush->bounds().h; |
70 | brushCenter = brush->center().y; |
71 | } |
72 | } |
73 | |
74 | const bool isDynamic = loop->getDynamics().isDynamic(); |
75 | for (const auto& pt : refStroke) { |
76 | if (isDynamic) { |
77 | brushSize = pt.size; |
78 | brushCenter = (brushSize - brushSize % 2) / 2; |
79 | } |
80 | Stroke::Pt pt2 = pt; |
81 | pt2.symmetry = symmetryMode; |
82 | if (symmetryMode == gen::SymmetryMode::HORIZONTAL || symmetryMode == gen::SymmetryMode::BOTH) |
83 | pt2.x = 2 * (m_x + brushCenter) - pt2.x - brushSize; |
84 | else |
85 | pt2.y = 2 * (m_y + brushCenter) - pt2.y - brushSize; |
86 | stroke.addPoint(pt2); |
87 | } |
88 | } |
89 | |
90 | } // namespace tools |
91 | } // namespace app |
92 | |