mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-01 10:13:22 +00:00
Add "Sprite Grid" source option to Export Sprite Sheet (fix #1982)
In this way we can export each grid cell/tile as an individual sprite, and use the extrude option on each grid cell. We've added the --split-grid CLI option too.
This commit is contained in:
parent
a2f61a3378
commit
acb246e26b
@ -540,6 +540,7 @@
|
||||
<option id="frame_tag" type="std::string" />
|
||||
<option id="split_layers" type="bool" default="false" />
|
||||
<option id="split_tags" type="bool" default="false" />
|
||||
<option id="split_grid" type="bool" default="false" />
|
||||
<option id="list_layers" type="bool" default="true" />
|
||||
<option id="list_frame_tags" type="bool" default="true" />
|
||||
<option id="list_slices" type="bool" default="true" />
|
||||
|
@ -49,6 +49,7 @@ AppOptions::AppOptions(int argc, const char* argv[])
|
||||
, m_splitLayers(m_po.add("split-layers").description("Save each visible layer of sprites\nas separated images in the sheet\n"))
|
||||
, m_splitTags(m_po.add("split-tags").description("Save each tag as a separated file"))
|
||||
, m_splitSlices(m_po.add("split-slices").description("Save each slice as a separated file"))
|
||||
, m_splitGrid(m_po.add("split-grid").description("Save each grid tile as a separated file"))
|
||||
, m_layer(m_po.add("layer").alias("import-layer").requiresValue("<name>").description("Include just the given layer in the sheet\nor save as operation"))
|
||||
, m_allLayers(m_po.add("all-layers").description("Make all layers visible\nBy default hidden layers will be ignored"))
|
||||
, m_ignoreLayer(m_po.add("ignore-layer").requiresValue("<name>").description("Exclude the given layer in the sheet\nor save as operation"))
|
||||
|
@ -65,6 +65,7 @@ public:
|
||||
const Option& splitLayers() const { return m_splitLayers; }
|
||||
const Option& splitTags() const { return m_splitTags; }
|
||||
const Option& splitSlices() const { return m_splitSlices; }
|
||||
const Option& splitGrid() const { return m_splitGrid; }
|
||||
const Option& layer() const { return m_layer; }
|
||||
const Option& allLayers() const { return m_allLayers; }
|
||||
const Option& ignoreLayer() const { return m_ignoreLayer; }
|
||||
@ -132,6 +133,7 @@ private:
|
||||
Option& m_splitLayers;
|
||||
Option& m_splitTags;
|
||||
Option& m_splitSlices;
|
||||
Option& m_splitGrid;
|
||||
Option& m_layer;
|
||||
Option& m_allLayers;
|
||||
Option& m_ignoreLayer;
|
||||
|
@ -33,6 +33,7 @@ namespace app {
|
||||
bool splitLayers = false;
|
||||
bool splitTags = false;
|
||||
bool splitSlices = false;
|
||||
bool splitGrid = false;
|
||||
bool allLayers = false;
|
||||
bool listLayers = false;
|
||||
bool listTags = false;
|
||||
|
@ -283,6 +283,10 @@ int CliProcessor::process(Context* ctx)
|
||||
else if (opt == &m_options.splitSlices()) {
|
||||
cof.splitSlices = true;
|
||||
}
|
||||
// --split-grid
|
||||
else if (opt == &m_options.splitGrid()) {
|
||||
cof.splitGrid = true;
|
||||
}
|
||||
// --layer <layer-name>
|
||||
else if (opt == &m_options.layer()) {
|
||||
cof.includeLayers.push_back(value.value());
|
||||
@ -691,6 +695,7 @@ bool CliProcessor::openFile(Context* ctx, CliOpenFile& cof)
|
||||
doc, tag,
|
||||
cof.splitLayers,
|
||||
cof.splitTags,
|
||||
cof.splitGrid,
|
||||
(cof.hasLayersFilter() ? &filteredLayers: nullptr),
|
||||
(!selFrames.empty() ? &selFrames: nullptr));
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ enum Section {
|
||||
|
||||
enum Source {
|
||||
kSource_Sprite,
|
||||
kSource_SpriteGrid,
|
||||
kSource_Tilesets,
|
||||
};
|
||||
|
||||
@ -171,6 +172,7 @@ Doc* generate_sprite_sheet_from_params(
|
||||
const bool mergeDuplicates = params.mergeDuplicates();
|
||||
const bool splitLayers = params.splitLayers();
|
||||
const bool splitTags = params.splitTags();
|
||||
const bool splitGrid = params.splitGrid();
|
||||
const bool listLayers = params.listLayers();
|
||||
const bool listTags = params.listTags();
|
||||
const bool listSlices = params.listSlices();
|
||||
@ -204,13 +206,17 @@ Doc* generate_sprite_sheet_from_params(
|
||||
}
|
||||
|
||||
exporter.reset();
|
||||
if (fromTilesets)
|
||||
|
||||
// Use each tileset from tilemap layers as a sprite
|
||||
if (fromTilesets) {
|
||||
exporter.addTilesetsSamples(
|
||||
doc,
|
||||
!selLayers.empty() ? &selLayers: nullptr);
|
||||
}
|
||||
// Use the whole canvas as a sprite
|
||||
else {
|
||||
exporter.addDocumentSamples(
|
||||
doc, tag, splitLayers, splitTags,
|
||||
doc, tag, splitLayers, splitTags, splitGrid,
|
||||
!selLayers.empty() ? &selLayers: nullptr,
|
||||
!selFrames.empty() ? &selFrames: nullptr);
|
||||
}
|
||||
@ -358,11 +364,15 @@ public:
|
||||
}
|
||||
|
||||
static_assert(kSource_Sprite == 0 &&
|
||||
kSource_Tilesets == 1,
|
||||
kSource_SpriteGrid == 1 &&
|
||||
kSource_Tilesets == 2,
|
||||
"Source enum has changed");
|
||||
source()->addItem(new ListItem("Sprite"));
|
||||
source()->addItem(new ListItem("Sprite Grid"));
|
||||
source()->addItem(new ListItem("Tilesets"));
|
||||
if (params.fromTilesets())
|
||||
if (params.splitGrid())
|
||||
source()->setSelectedItemIndex(int(kSource_SpriteGrid));
|
||||
else if (params.fromTilesets())
|
||||
source()->setSelectedItemIndex(int(kSource_Tilesets));
|
||||
|
||||
fill_layers_combobox(
|
||||
@ -529,6 +539,7 @@ public:
|
||||
params.listLayers (listLayersValue());
|
||||
params.listTags (listTagsValue());
|
||||
params.listSlices (listSlicesValue());
|
||||
params.splitGrid (source()->getSelectedItemIndex() == int(kSource_SpriteGrid));
|
||||
params.fromTilesets (source()->getSelectedItemIndex() == int(kSource_Tilesets));
|
||||
}
|
||||
|
||||
@ -721,6 +732,10 @@ private:
|
||||
return splitTags()->isSelected();
|
||||
}
|
||||
|
||||
bool splitGridValue() const {
|
||||
return (source()->getSelectedItemIndex() == int(kSource_SpriteGrid));
|
||||
}
|
||||
|
||||
bool listLayersValue() const {
|
||||
return listLayers()->isSelected();
|
||||
}
|
||||
@ -1222,6 +1237,7 @@ void ExportSpriteSheetCommand::onExecute(Context* context)
|
||||
if (!params.tag.isSet()) params.tag( defPref.spriteSheet.frameTag());
|
||||
if (!params.splitLayers.isSet()) params.splitLayers( defPref.spriteSheet.splitLayers());
|
||||
if (!params.splitTags.isSet()) params.splitTags( defPref.spriteSheet.splitTags());
|
||||
if (!params.splitGrid.isSet()) params.splitGrid( defPref.spriteSheet.splitGrid());
|
||||
if (!params.listLayers.isSet()) params.listLayers( defPref.spriteSheet.listLayers());
|
||||
if (!params.listTags.isSet()) params.listTags( defPref.spriteSheet.listFrameTags());
|
||||
if (!params.listSlices.isSet()) params.listSlices( defPref.spriteSheet.listSlices());
|
||||
@ -1268,6 +1284,7 @@ void ExportSpriteSheetCommand::onExecute(Context* context)
|
||||
docPref.spriteSheet.frameTag (params.tag());
|
||||
docPref.spriteSheet.splitLayers (params.splitLayers());
|
||||
docPref.spriteSheet.splitTags (params.splitTags());
|
||||
docPref.spriteSheet.splitGrid (params.splitGrid());
|
||||
docPref.spriteSheet.listLayers (params.listLayers());
|
||||
docPref.spriteSheet.listFrameTags (params.listTags());
|
||||
docPref.spriteSheet.listSlices (params.listSlices());
|
||||
|
@ -43,6 +43,7 @@ struct ExportSpriteSheetParams : public NewParams {
|
||||
Param<std::string> tag { this, std::string(), "tag" };
|
||||
Param<bool> splitLayers { this, false, "splitLayers" };
|
||||
Param<bool> splitTags { this, false, "splitTags" };
|
||||
Param<bool> splitGrid { this, false, "splitGrid" };
|
||||
Param<bool> listLayers { this, true, "listLayers" };
|
||||
Param<bool> listTags { this, true, "listTags" };
|
||||
Param<bool> listSlices { this, true, "listSlices" };
|
||||
|
@ -96,11 +96,13 @@ typedef std::shared_ptr<gfx::Rect> SharedRectPtr;
|
||||
DocExporter::Item::Item(Doc* doc,
|
||||
const doc::Tag* tag,
|
||||
const doc::SelectedLayers* selLayers,
|
||||
const doc::SelectedFrames* selFrames)
|
||||
const doc::SelectedFrames* selFrames,
|
||||
const bool splitGrid)
|
||||
: doc(doc)
|
||||
, tag(tag)
|
||||
, selLayers(selLayers ? std::make_unique<doc::SelectedLayers>(*selLayers): nullptr)
|
||||
, selFrames(selFrames ? std::make_unique<doc::SelectedFrames>(*selFrames): nullptr)
|
||||
, splitGrid(splitGrid)
|
||||
{
|
||||
}
|
||||
|
||||
@ -146,7 +148,8 @@ doc::SelectedFrames DocExporter::Item::getSelectedFrames() const
|
||||
|
||||
class DocExporter::Sample {
|
||||
public:
|
||||
Sample(Doc* document,
|
||||
Sample(const gfx::Size& size,
|
||||
Doc* document,
|
||||
Sprite* sprite,
|
||||
const ImageRef& image,
|
||||
SelectedLayers* selLayers,
|
||||
@ -166,10 +169,9 @@ public:
|
||||
m_extrude(extrude),
|
||||
m_isLinked(false),
|
||||
m_isDuplicated(false),
|
||||
m_originalSize(image ? image->width(): sprite->width(),
|
||||
image ? image->height(): sprite->height()),
|
||||
m_trimmedBounds(m_originalSize),
|
||||
m_inTextureBounds(std::make_shared<gfx::Rect>(m_trimmedBounds)) {
|
||||
m_originalSize(size),
|
||||
m_trimmedBounds(size),
|
||||
m_inTextureBounds(std::make_shared<gfx::Rect>(size)) {
|
||||
}
|
||||
|
||||
Doc* document() const { return m_document; }
|
||||
@ -732,10 +734,11 @@ void DocExporter::addDocument(
|
||||
Doc* doc,
|
||||
const doc::Tag* tag,
|
||||
const doc::SelectedLayers* selLayers,
|
||||
const doc::SelectedFrames* selFrames)
|
||||
const doc::SelectedFrames* selFrames,
|
||||
const bool splitGrid)
|
||||
{
|
||||
DX_TRACE("DX: addDocument doc=", doc, "tag=", tag);
|
||||
m_documents.push_back(Item(doc, tag, selLayers, selFrames));
|
||||
m_documents.push_back(Item(doc, tag, selLayers, selFrames, splitGrid));
|
||||
}
|
||||
|
||||
void DocExporter::addImage(
|
||||
@ -751,6 +754,7 @@ int DocExporter::addDocumentSamples(
|
||||
const doc::Tag* thisTag,
|
||||
const bool splitLayers,
|
||||
const bool splitTags,
|
||||
const bool splitGrid,
|
||||
const doc::SelectedLayers* selLayers,
|
||||
const doc::SelectedFrames* selFrames)
|
||||
{
|
||||
@ -819,7 +823,7 @@ int DocExporter::addDocumentSamples(
|
||||
|
||||
SelectedLayers oneLayer;
|
||||
oneLayer.insert(layer);
|
||||
addDocument(doc, tag, &oneLayer, thisSelFrames);
|
||||
addDocument(doc, tag, &oneLayer, thisSelFrames, splitGrid);
|
||||
++items;
|
||||
}
|
||||
}
|
||||
@ -830,13 +834,13 @@ int DocExporter::addDocumentSamples(
|
||||
|
||||
SelectedLayers oneLayer;
|
||||
oneLayer.insert(layer);
|
||||
addDocument(doc, tag, &oneLayer, thisSelFrames);
|
||||
addDocument(doc, tag, &oneLayer, thisSelFrames, splitGrid);
|
||||
++items;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
addDocument(doc, tag, selLayers, thisSelFrames);
|
||||
addDocument(doc, tag, selLayers, thisSelFrames, splitGrid);
|
||||
++items;
|
||||
}
|
||||
}
|
||||
@ -957,6 +961,9 @@ void DocExporter::captureSamples(Samples& samples,
|
||||
std::string filename = filename_formatter(format, fnInfo);
|
||||
|
||||
Sample sample(
|
||||
(item.image ? item.image->size():
|
||||
item.splitGrid ? sprite->gridBounds().size():
|
||||
sprite->size()),
|
||||
doc, sprite, item.image, item.selLayers.get(),
|
||||
frame, innerTag, filename,
|
||||
m_innerPadding, m_extrude);
|
||||
@ -1063,7 +1070,23 @@ void DocExporter::captureSamples(Samples& samples,
|
||||
if (!alreadyTrimmed && m_trimSprite)
|
||||
sample.setTrimmedBounds(spriteBounds);
|
||||
|
||||
samples.addSample(sample);
|
||||
if (item.splitGrid) {
|
||||
const gfx::Rect& gridBounds = sprite->gridBounds();
|
||||
gfx::Point initPos(0, 0), pos;
|
||||
initPos = pos = snap_to_grid(gridBounds, initPos, PreferSnapTo::BoxOrigin);
|
||||
|
||||
for (; pos.y+gridBounds.h <= spriteBounds.h; pos.y+=gridBounds.h) {
|
||||
for (pos.x=initPos.x; pos.x+gridBounds.w <= spriteBounds.w; pos.x+=gridBounds.w) {
|
||||
const gfx::Rect cellBounds(pos, gridBounds.size());
|
||||
sample.setTrimmedBounds(cellBounds);
|
||||
sample.setSharedBounds(std::make_shared<gfx::Rect>(sample.inTextureBounds()));
|
||||
samples.addSample(sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
samples.addSample(sample);
|
||||
}
|
||||
|
||||
DX_TRACE("DX: - Sample:",
|
||||
sample.document()->filename(),
|
||||
|
@ -77,12 +77,6 @@ namespace app {
|
||||
void setListLayers(bool value) { m_listLayers = value; }
|
||||
void setListSlices(bool value) { m_listSlices = value; }
|
||||
|
||||
void addDocument(
|
||||
Doc* doc,
|
||||
const doc::Tag* tag,
|
||||
const doc::SelectedLayers* selLayers,
|
||||
const doc::SelectedFrames* selFrames);
|
||||
|
||||
void addImage(
|
||||
Doc* doc,
|
||||
const doc::ImageRef& image);
|
||||
@ -92,6 +86,7 @@ namespace app {
|
||||
const doc::Tag* tag,
|
||||
const bool splitLayers,
|
||||
const bool splitTags,
|
||||
const bool splitGrid,
|
||||
const doc::SelectedLayers* selLayers,
|
||||
const doc::SelectedFrames* selFrames);
|
||||
|
||||
@ -109,6 +104,12 @@ namespace app {
|
||||
class SimpleLayoutSamples;
|
||||
class BestFitLayoutSamples;
|
||||
|
||||
void addDocument(
|
||||
Doc* doc,
|
||||
const doc::Tag* tag,
|
||||
const doc::SelectedLayers* selLayers,
|
||||
const doc::SelectedFrames* selFrames,
|
||||
const bool splitGrid);
|
||||
void captureSamples(Samples& samples,
|
||||
base::task_token& token);
|
||||
void layoutSamples(Samples& samples,
|
||||
@ -130,12 +131,14 @@ namespace app {
|
||||
const doc::Tag* tag = nullptr;
|
||||
std::unique_ptr<doc::SelectedLayers> selLayers;
|
||||
std::unique_ptr<doc::SelectedFrames> selFrames;
|
||||
bool splitGrid = false;
|
||||
doc::ImageRef image;
|
||||
|
||||
Item(Doc* doc,
|
||||
const doc::Tag* tag,
|
||||
const doc::SelectedLayers* selLayers,
|
||||
const doc::SelectedFrames* selFrames);
|
||||
const doc::SelectedFrames* selFrames,
|
||||
const bool splitGrid);
|
||||
Item(Doc* doc,
|
||||
const doc::ImageRef& image);
|
||||
Item(Item&& other);
|
||||
|
Loading…
x
Reference in New Issue
Block a user