1 | // Aseprite |
2 | // Copyright (C) 2019-2022 Igara Studio S.A. |
3 | // Copyright (C) 2001-2016 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/background_from_layer.h" |
13 | |
14 | #include "app/cmd/add_cel.h" |
15 | #include "app/cmd/configure_background.h" |
16 | #include "app/cmd/copy_rect.h" |
17 | #include "app/cmd/replace_image.h" |
18 | #include "app/cmd/set_cel_opacity.h" |
19 | #include "app/cmd/set_cel_position.h" |
20 | #include "app/doc.h" |
21 | #include "doc/cel.h" |
22 | #include "doc/image.h" |
23 | #include "doc/layer.h" |
24 | #include "doc/primitives.h" |
25 | #include "doc/sprite.h" |
26 | #include "render/render.h" |
27 | |
28 | namespace app { |
29 | namespace cmd { |
30 | |
31 | BackgroundFromLayer::BackgroundFromLayer(Layer* layer) |
32 | : WithLayer(layer) |
33 | { |
34 | ASSERT(layer); |
35 | ASSERT(layer->isVisible()); |
36 | ASSERT(layer->isEditable()); |
37 | ASSERT(!layer->isReference()); |
38 | ASSERT(layer->sprite() != NULL); |
39 | ASSERT(layer->sprite()->backgroundLayer() == NULL); |
40 | } |
41 | |
42 | void BackgroundFromLayer::onExecute() |
43 | { |
44 | Layer* layer = this->layer(); |
45 | ASSERT(!layer->isTilemap()); // TODO support background tilemaps |
46 | |
47 | Sprite* sprite = layer->sprite(); |
48 | auto doc = static_cast<Doc*>(sprite->document()); |
49 | color_t bgcolor = doc->bgColor(); |
50 | |
51 | // Create a temporary image to draw each cel of the new Background |
52 | // layer. |
53 | ImageRef bg_image(Image::create(sprite->spec())); |
54 | |
55 | CelList cels; |
56 | layer->getCels(cels); |
57 | for (Cel* cel : cels) { |
58 | Image* cel_image = cel->image(); |
59 | ASSERT(cel_image); |
60 | ASSERT(cel_image->pixelFormat() != IMAGE_TILEMAP); |
61 | |
62 | clear_image(bg_image.get(), bgcolor); |
63 | render::composite_image( |
64 | bg_image.get(), cel_image, |
65 | sprite->palette(cel->frame()), |
66 | cel->x(), cel->y(), |
67 | std::clamp(cel->opacity(), 0, 255), |
68 | static_cast<LayerImage*>(layer)->blendMode()); |
69 | |
70 | // now we have to copy the new image (bg_image) to the cel... |
71 | executeAndAdd(new cmd::SetCelPosition(cel, 0, 0)); |
72 | |
73 | // change opacity to 255 |
74 | if (cel->opacity() < 255) |
75 | executeAndAdd(new cmd::SetCelOpacity(cel, 255)); |
76 | |
77 | // Same size of cel image and background image, we can just |
78 | // replace pixels. |
79 | if (bg_image->width() == cel_image->width() && |
80 | bg_image->height() == cel_image->height()) { |
81 | executeAndAdd(new CopyRect(cel_image, bg_image.get(), |
82 | gfx::Clip(0, 0, cel_image->bounds()))); |
83 | } |
84 | // In other case we have to replace the whole image (this is the |
85 | // most common case, a smaller transparent cel that is converted |
86 | // to a canvas size cel in the background) |
87 | else { |
88 | ImageRef bg_image2(Image::createCopy(bg_image.get())); |
89 | executeAndAdd(new cmd::ReplaceImage(sprite, cel->imageRef(), bg_image2)); |
90 | } |
91 | } |
92 | |
93 | // Fill all empty cels with a flat image filled with bgcolor |
94 | for (frame_t frame(0); frame<sprite->totalFrames(); ++frame) { |
95 | Cel* cel = layer->cel(frame); |
96 | if (!cel) { |
97 | ImageRef cel_image(Image::create(sprite->pixelFormat(), |
98 | sprite->width(), sprite->height())); |
99 | clear_image(cel_image.get(), bgcolor); |
100 | |
101 | // Create the new cel and add it to the new background layer |
102 | cel = new Cel(frame, cel_image); |
103 | executeAndAdd(new cmd::AddCel(layer, cel)); |
104 | } |
105 | } |
106 | |
107 | executeAndAdd(new cmd::ConfigureBackground(layer)); |
108 | } |
109 | |
110 | } // namespace cmd |
111 | } // namespace app |
112 | |