diff --git a/data/pref.xml b/data/pref.xml
index bc7fdac07..d59e8f464 100644
--- a/data/pref.xml
+++ b/data/pref.xml
@@ -540,6 +540,7 @@
+
diff --git a/src/app/cli/app_options.cpp b/src/app/cli/app_options.cpp
index 914a85176..dd9af9e6d 100644
--- a/src/app/cli/app_options.cpp
+++ b/src/app/cli/app_options.cpp
@@ -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("").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("").description("Exclude the given layer in the sheet\nor save as operation"))
diff --git a/src/app/cli/app_options.h b/src/app/cli/app_options.h
index 6c2b2b688..48816ac27 100644
--- a/src/app/cli/app_options.h
+++ b/src/app/cli/app_options.h
@@ -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;
diff --git a/src/app/cli/cli_open_file.h b/src/app/cli/cli_open_file.h
index c5d262a48..4fec4591d 100644
--- a/src/app/cli/cli_open_file.h
+++ b/src/app/cli/cli_open_file.h
@@ -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;
diff --git a/src/app/cli/cli_processor.cpp b/src/app/cli/cli_processor.cpp
index c48b70865..b74a4b792 100644
--- a/src/app/cli/cli_processor.cpp
+++ b/src/app/cli/cli_processor.cpp
@@ -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
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));
}
diff --git a/src/app/commands/cmd_export_sprite_sheet.cpp b/src/app/commands/cmd_export_sprite_sheet.cpp
index 80028fdf0..040ae0758 100644
--- a/src/app/commands/cmd_export_sprite_sheet.cpp
+++ b/src/app/commands/cmd_export_sprite_sheet.cpp
@@ -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());
diff --git a/src/app/commands/cmd_export_sprite_sheet.h b/src/app/commands/cmd_export_sprite_sheet.h
index bbde5f427..8ab114f69 100644
--- a/src/app/commands/cmd_export_sprite_sheet.h
+++ b/src/app/commands/cmd_export_sprite_sheet.h
@@ -43,6 +43,7 @@ struct ExportSpriteSheetParams : public NewParams {
Param tag { this, std::string(), "tag" };
Param splitLayers { this, false, "splitLayers" };
Param splitTags { this, false, "splitTags" };
+ Param splitGrid { this, false, "splitGrid" };
Param listLayers { this, true, "listLayers" };
Param listTags { this, true, "listTags" };
Param listSlices { this, true, "listSlices" };
diff --git a/src/app/doc_exporter.cpp b/src/app/doc_exporter.cpp
index ee479caa8..3927d60da 100644
--- a/src/app/doc_exporter.cpp
+++ b/src/app/doc_exporter.cpp
@@ -96,11 +96,13 @@ typedef std::shared_ptr 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(*selLayers): nullptr)
, selFrames(selFrames ? std::make_unique(*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(m_trimmedBounds)) {
+ m_originalSize(size),
+ m_trimmedBounds(size),
+ m_inTextureBounds(std::make_shared(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(sample.inTextureBounds()));
+ samples.addSample(sample);
+ }
+ }
+ }
+ else {
+ samples.addSample(sample);
+ }
DX_TRACE("DX: - Sample:",
sample.document()->filename(),
diff --git a/src/app/doc_exporter.h b/src/app/doc_exporter.h
index 2abccad89..2cc12f367 100644
--- a/src/app/doc_exporter.h
+++ b/src/app/doc_exporter.h
@@ -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 selLayers;
std::unique_ptr 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);