1// Aseprite
2// Copyright (C) 2019 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/move_cel.h"
13
14#include "app/cmd/add_cel.h"
15#include "app/cmd/add_frame.h"
16#include "app/cmd/clear_cel.h"
17#include "app/cmd/clear_image.h"
18#include "app/cmd/copy_rect.h"
19#include "app/cmd/remove_cel.h"
20#include "app/cmd/set_cel_data.h"
21#include "app/cmd/set_cel_frame.h"
22#include "app/cmd/unlink_cel.h"
23#include "app/doc.h"
24#include "app/util/cel_ops.h"
25#include "doc/cel.h"
26#include "doc/layer.h"
27#include "doc/primitives.h"
28#include "doc/sprite.h"
29#include "render/rasterize.h"
30#include "render/render.h"
31
32namespace app {
33namespace cmd {
34
35using namespace doc;
36
37MoveCel::MoveCel(
38 LayerImage* srcLayer, frame_t srcFrame,
39 LayerImage* dstLayer, frame_t dstFrame, bool continuous)
40 : m_srcLayer(srcLayer)
41 , m_dstLayer(dstLayer)
42 , m_srcFrame(srcFrame)
43 , m_dstFrame(dstFrame)
44 , m_continuous(continuous)
45{
46}
47
48void MoveCel::onExecute()
49{
50 LayerImage* srcLayer = static_cast<LayerImage*>(m_srcLayer.layer());
51 LayerImage* dstLayer = static_cast<LayerImage*>(m_dstLayer.layer());
52
53 ASSERT(srcLayer);
54 ASSERT(dstLayer);
55
56 Sprite* srcSprite = srcLayer->sprite();
57 Sprite* dstSprite = dstLayer->sprite();
58 ASSERT(srcSprite);
59 ASSERT(dstSprite);
60 ASSERT(m_srcFrame >= 0 && m_srcFrame < srcSprite->totalFrames());
61 ASSERT(m_dstFrame >= 0);
62
63 Cel* srcCel = srcLayer->cel(m_srcFrame);
64 Cel* dstCel = dstLayer->cel(m_dstFrame);
65
66 // Clear destination cel if it does exist. It'll be overriden by the
67 // copy of srcCel.
68 if (dstCel) {
69 if (dstCel->links())
70 executeAndAdd(new cmd::UnlinkCel(dstCel));
71 executeAndAdd(new cmd::ClearCel(dstCel));
72 }
73
74 // Add empty frames until newFrame
75 while (dstSprite->totalFrames() <= m_dstFrame)
76 executeAndAdd(new cmd::AddFrame(dstSprite, dstSprite->totalFrames()));
77
78 Image* srcImage = (srcCel ? srcCel->image(): NULL);
79 ImageRef dstImage;
80 dstCel = dstLayer->cel(m_dstFrame);
81 if (dstCel)
82 dstImage = dstCel->imageRef();
83
84 bool createLink =
85 (srcLayer == dstLayer && m_continuous);
86
87 // For background layer
88 if (dstLayer->isBackground()) {
89 ASSERT(dstCel);
90 ASSERT(dstImage);
91 if (!dstCel || !dstImage ||
92 !srcCel || !srcImage)
93 return;
94
95 ASSERT(!dstLayer->isTilemap()); // TODO support background tilemaps
96
97 if (createLink) {
98 executeAndAdd(new cmd::SetCelData(dstCel, srcCel->dataRef()));
99 executeAndAdd(new cmd::UnlinkCel(srcCel));
100 }
101 // Rasterize tilemap into the regular image background layer
102 else if (srcLayer->isTilemap()) {
103 ImageRef tmp(Image::createCopy(dstImage.get()));
104 render::rasterize(tmp.get(), srcCel, 0, 0, false);
105 executeAndAdd(new cmd::CopyRect(dstImage.get(), tmp.get(), gfx::Clip(tmp->bounds())));
106 }
107 else {
108 BlendMode blend = (srcLayer->isBackground() ?
109 BlendMode::SRC:
110 BlendMode::NORMAL);
111
112 ImageRef tmp(Image::createCopy(dstImage.get()));
113 render::composite_image(
114 tmp.get(), srcImage,
115 srcSprite->palette(m_srcFrame),
116 srcCel->x(), srcCel->y(), 255, blend);
117 executeAndAdd(new cmd::CopyRect(dstImage.get(), tmp.get(), gfx::Clip(tmp->bounds())));
118 }
119 executeAndAdd(new cmd::ClearCel(srcCel));
120 }
121 // For transparent layers
122 else if (srcCel) {
123 ASSERT(!dstCel);
124 if (dstCel)
125 return;
126
127 // Move the cel in the same layer.
128 if (srcLayer == dstLayer) {
129 executeAndAdd(new cmd::SetCelFrame(srcCel, m_dstFrame));
130 }
131 else {
132 dstCel = create_cel_copy(this, srcCel, dstSprite, dstLayer, m_dstFrame);
133
134 executeAndAdd(new cmd::AddCel(dstLayer, dstCel));
135 executeAndAdd(new cmd::ClearCel(srcCel));
136 }
137 }
138}
139
140void MoveCel::onFireNotifications()
141{
142 CmdSequence::onFireNotifications();
143 static_cast<Doc*>(m_dstLayer.layer()->sprite()->document())
144 ->notifyCelMoved(
145 m_srcLayer.layer(), m_srcFrame,
146 m_dstLayer.layer(), m_dstFrame);
147}
148
149} // namespace cmd
150} // namespace app
151