| 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 | |