1// Aseprite
2// Copyright (C) 2019-2022 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#ifndef APP_DOC_EXPORTER_H_INCLUDED
9#define APP_DOC_EXPORTER_H_INCLUDED
10#pragma once
11
12#include "app/sprite_sheet_data_format.h"
13#include "app/sprite_sheet_type.h"
14#include "base/disable_copying.h"
15#include "base/task.h"
16#include "doc/frame.h"
17#include "doc/image_ref.h"
18#include "doc/image_buffer.h"
19#include "doc/object_id.h"
20#include "doc/object_version.h"
21#include "gfx/fwd.h"
22#include "gfx/rect.h"
23
24#include <iosfwd>
25#include <memory>
26#include <string>
27#include <utility>
28#include <vector>
29
30namespace doc {
31 class Image;
32 class SelectedFrames;
33 class SelectedLayers;
34 class Sprite;
35 class Tag;
36}
37
38namespace app {
39
40 class Context;
41 class Doc;
42
43 class DocExporter {
44 public:
45 DocExporter();
46
47 void reset();
48 void setDocImageBuffer(const doc::ImageBufferPtr& docBuf);
49
50 SpriteSheetDataFormat dataFormat() const { return m_dataFormat; }
51 const std::string& dataFilename() { return m_dataFilename; }
52 const std::string& textureFilename() { return m_textureFilename; }
53 SpriteSheetType spriteSheetType() { return m_sheetType; }
54 const std::string& filenameFormat() const { return m_filenameFormat; }
55
56 void setDataFormat(SpriteSheetDataFormat format) { m_dataFormat = format; }
57 void setDataFilename(const std::string& filename) { m_dataFilename = filename; }
58 void setTextureFilename(const std::string& filename) { m_textureFilename = filename; }
59 void setTextureWidth(int width) { m_textureWidth = width; }
60 void setTextureHeight(int height) { m_textureHeight = height; }
61 void setTextureColumns(int columns) { m_textureColumns = columns; }
62 void setTextureRows(int rows) { m_textureRows = rows; }
63 void setSpriteSheetType(SpriteSheetType type) { m_sheetType = type; }
64 void setIgnoreEmptyCels(bool ignore) { m_ignoreEmptyCels = ignore; }
65 void setMergeDuplicates(bool merge) { m_mergeDuplicates = merge; }
66 void setBorderPadding(int padding) { m_borderPadding = padding; }
67 void setShapePadding(int padding) { m_shapePadding = padding; }
68 void setInnerPadding(int padding) { m_innerPadding = padding; }
69 void setTrimSprite(bool trim) { m_trimSprite = trim; }
70 void setTrimCels(bool trim) { m_trimCels = trim; }
71 void setTrimByGrid(bool trimByGrid) { m_trimByGrid = trimByGrid; }
72 void setExtrude(bool extrude) { m_extrude = extrude; }
73 void setFilenameFormat(const std::string& format) { m_filenameFormat = format; }
74 void setSplitLayers(bool splitLayers) { m_splitLayers = splitLayers; }
75 void setSplitTags(bool splitTags) { m_splitTags = splitTags; }
76 void setListTags(bool value) { m_listTags = value; }
77 void setListLayers(bool value) { m_listLayers = value; }
78 void setListSlices(bool value) { m_listSlices = value; }
79
80 void addImage(
81 Doc* doc,
82 const doc::ImageRef& image);
83
84 int addDocumentSamples(
85 Doc* doc,
86 const doc::Tag* tag,
87 const bool splitLayers,
88 const bool splitTags,
89 const bool splitGrid,
90 const doc::SelectedLayers* selLayers,
91 const doc::SelectedFrames* selFrames);
92
93 int addTilesetsSamples(
94 Doc* doc,
95 const doc::SelectedLayers* selLayers);
96
97 Doc* exportSheet(Context* ctx, base::task_token& token);
98 gfx::Size calculateSheetSize();
99
100 private:
101 class Sample;
102 class Samples;
103 class LayoutSamples;
104 class SimpleLayoutSamples;
105 class BestFitLayoutSamples;
106
107 void addDocument(
108 Doc* doc,
109 const doc::Tag* tag,
110 const doc::SelectedLayers* selLayers,
111 const doc::SelectedFrames* selFrames,
112 const bool splitGrid);
113 void captureSamples(Samples& samples,
114 base::task_token& token);
115 void layoutSamples(Samples& samples,
116 base::task_token& token);
117 gfx::Size calculateSheetSize(const Samples& samples,
118 base::task_token& token) const;
119 Doc* createEmptyTexture(const Samples& samples,
120 base::task_token& token) const;
121 void renderTexture(Context* ctx,
122 const Samples& samples,
123 doc::Image* textureImage,
124 base::task_token& token) const;
125 void trimTexture(const Samples& samples, doc::Sprite* texture) const;
126 void createDataFile(const Samples& samples, std::ostream& os, doc::Sprite* texture);
127
128 class Item {
129 public:
130 Doc* doc = nullptr;
131 const doc::Tag* tag = nullptr;
132 std::unique_ptr<doc::SelectedLayers> selLayers;
133 std::unique_ptr<doc::SelectedFrames> selFrames;
134 bool splitGrid = false;
135 doc::ImageRef image;
136
137 Item(Doc* doc,
138 const doc::Tag* tag,
139 const doc::SelectedLayers* selLayers,
140 const doc::SelectedFrames* selFrames,
141 const bool splitGrid);
142 Item(Doc* doc,
143 const doc::ImageRef& image);
144 Item(Item&& other);
145 ~Item();
146
147 Item() = delete;
148 Item(const Item&) = delete;
149 Item& operator=(const Item&) = delete;
150
151 int frames() const;
152 doc::SelectedFrames getSelectedFrames() const;
153
154 bool isOneImageOnly() const { return image != nullptr; }
155 };
156 typedef std::vector<Item> Items;
157
158 SpriteSheetType m_sheetType;
159 SpriteSheetDataFormat m_dataFormat;
160 std::string m_dataFilename;
161 std::string m_textureFilename;
162 std::string m_filenameFormat;
163 int m_textureWidth;
164 int m_textureHeight;
165 int m_textureColumns;
166 int m_textureRows;
167 int m_borderPadding;
168 int m_shapePadding;
169 int m_innerPadding;
170 bool m_ignoreEmptyCels;
171 bool m_mergeDuplicates;
172 bool m_trimSprite;
173 bool m_trimCels;
174 bool m_trimByGrid;
175 bool m_extrude;
176 bool m_splitLayers;
177 bool m_splitTags;
178 bool m_listTags;
179 bool m_listLayers;
180 bool m_listSlices;
181 Items m_documents;
182
183 // Buffers used
184 doc::ImageBufferPtr m_docBuf;
185 doc::ImageBufferPtr m_sampleBuf;
186
187 // Trimmed bounds of a specific sprite (to avoid recalculating
188 // this)
189 struct Cache {
190 doc::ObjectId spriteId;
191 doc::ObjectVersion spriteVer;
192 gfx::Rect trimmedBounds;
193 bool trimmedByGrid;
194 } m_cache;
195
196 DISABLE_COPYING(DocExporter);
197 };
198
199} // namespace app
200
201#endif
202