1// Aseprite
2// Copyright (C) 2020 Igara Studio S.A.
3// Copyright (C) 2001-2018 David Capello
4//
5// This program is distributed under the terms of
6// the End-User License Agreement for Aseprite.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "app/cmd/clear_mask.h"
13
14#include "app/cmd/clear_cel.h"
15#include "app/doc.h"
16#include "doc/algorithm/fill_selection.h"
17#include "doc/cel.h"
18#include "doc/image_impl.h"
19#include "doc/layer.h"
20#include "doc/layer_tilemap.h"
21#include "doc/mask.h"
22#include "doc/primitives.h"
23
24namespace app {
25namespace cmd {
26
27using namespace doc;
28
29ClearMask::ClearMask(Cel* cel)
30 : WithCel(cel)
31{
32 Doc* doc = static_cast<Doc*>(cel->document());
33
34 // If the mask is empty or is not visible then we have to clear the
35 // entire image in the cel.
36 if (!doc->isMaskVisible()) {
37 m_seq.add(new cmd::ClearCel(cel));
38
39 // In this case m_copy will be nullptr, so the clear()/restore()
40 // member functions will have no effect.
41 return;
42 }
43
44 Image* image = cel->image();
45 assert(image);
46 if (!image)
47 return;
48
49 const Mask* mask = doc->mask();
50 gfx::Rect imageBounds;
51 gfx::Rect maskBounds;
52 if (image->pixelFormat() == IMAGE_TILEMAP) {
53 auto grid = cel->grid();
54 imageBounds = gfx::Rect(grid.canvasToTile(cel->position()),
55 cel->image()->size());
56 maskBounds = grid.canvasToTile(mask->bounds());
57 m_bgcolor = doc::notile; // TODO configurable empty tile
58 }
59 else {
60 imageBounds = cel->bounds();
61 maskBounds = mask->bounds();
62 m_bgcolor = doc->bgColor(cel->layer());
63 }
64
65 gfx::Rect cropBounds = (imageBounds & maskBounds);
66 if (cropBounds.isEmpty())
67 return;
68
69 cropBounds.offset(-imageBounds.origin());
70 m_cropPos = cropBounds.origin();
71
72 m_copy.reset(crop_image(image, cropBounds, m_bgcolor));
73}
74
75void ClearMask::onExecute()
76{
77 m_seq.execute(context());
78 clear();
79}
80
81void ClearMask::onUndo()
82{
83 restore();
84 m_seq.undo();
85}
86
87void ClearMask::onRedo()
88{
89 m_seq.redo();
90 clear();
91}
92
93void ClearMask::clear()
94{
95 if (!m_copy)
96 return;
97
98 Cel* cel = this->cel();
99 Doc* doc = static_cast<Doc*>(cel->document());
100 Mask* mask = doc->mask();
101
102 Grid grid = cel->grid();
103 doc::algorithm::fill_selection(
104 cel->image(),
105 cel->bounds(),
106 mask,
107 m_bgcolor,
108 (cel->image()->isTilemap() ? &grid: nullptr));
109}
110
111void ClearMask::restore()
112{
113 if (!m_copy)
114 return;
115
116 Cel* cel = this->cel();
117 copy_image(cel->image(),
118 m_copy.get(),
119 m_cropPos.x,
120 m_cropPos.y);
121}
122
123} // namespace cmd
124} // namespace app
125