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
28namespace app {
29namespace cmd {
30
31BackgroundFromLayer::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
42void 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