Add split layers option in ExportSpriteSheet

This commit is contained in:
David Capello 2019-10-03 15:52:19 -03:00
parent 7a10139a87
commit d99e642c55
4 changed files with 135 additions and 52 deletions

View File

@ -460,6 +460,7 @@
<option id="open_generated" type="bool" default="false" /> <option id="open_generated" type="bool" default="false" />
<option id="layer" type="std::string" /> <option id="layer" type="std::string" />
<option id="frame_tag" type="std::string" /> <option id="frame_tag" type="std::string" />
<option id="split_layers" type="bool" default="false" />
<option id="list_layers" type="bool" default="true" /> <option id="list_layers" type="bool" default="true" />
<option id="list_frame_tags" type="bool" default="true" /> <option id="list_frame_tags" type="bool" default="true" />
<option id="list_slices" type="bool" default="true" /> <option id="list_slices" type="bool" default="true" />

View File

@ -548,6 +548,10 @@ width = Width:
height = Height: height = Height:
best_fit = Best fit for texture best_fit = Best fit for texture
layers = Layers: layers = Layers:
split_layers = Split
split_layers_tooltip = <<<END
Generates one sprite for each layer (and for each frame).
END
frames = Frames: frames = Frames:
output_file = Output File output_file = Output File
json_data = JSON Data json_data = JSON Data

View File

@ -43,7 +43,8 @@
<check cell_hspan="3" id="best_fit" text="@.best_fit" /> <check cell_hspan="3" id="best_fit" text="@.best_fit" />
<label text="@.layers" /> <label text="@.layers" />
<combobox id="layers" text="" cell_hspan="3" /> <combobox id="layers" text="" cell_hspan="2" />
<check id="split_layers" text="@.split_layers" tooltip="@.split_layers_tooltip" />
<label text="@.frames" /> <label text="@.frames" />
<combobox id="frames" text="" cell_hspan="3" /> <combobox id="frames" text="" cell_hspan="3" />

View File

@ -194,6 +194,7 @@ struct ExportSpriteSheetParams : public NewParams {
Param<bool> openGenerated { this, false, "openGenerated" }; Param<bool> openGenerated { this, false, "openGenerated" };
Param<std::string> layer { this, std::string(), "layer" }; Param<std::string> layer { this, std::string(), "layer" };
Param<std::string> tag { this, std::string(), "tag" }; Param<std::string> tag { this, std::string(), "tag" };
Param<bool> splitLayers { this, false, "splitLayers" };
Param<bool> listLayers { this, true, "listLayers" }; Param<bool> listLayers { this, true, "listLayers" };
Param<bool> listTags { this, true, "listTags" }; Param<bool> listTags { this, true, "listTags" };
Param<bool> listSlices { this, true, "listSlices" }; Param<bool> listSlices { this, true, "listSlices" };
@ -221,16 +222,17 @@ void update_doc_exporter_from_params(const Site& site,
const bool trimByGrid = params.trimByGrid(); const bool trimByGrid = params.trimByGrid();
const bool extrude = params.extrude(); const bool extrude = params.extrude();
const int extrudePadding = (extrude ? 1: 0); const int extrudePadding = (extrude ? 1: 0);
const bool splitLayers = params.splitLayers();
const bool listLayers = params.listLayers(); const bool listLayers = params.listLayers();
const bool listTags = params.listTags(); const bool listTags = params.listTags();
const bool listSlices = params.listSlices(); const bool listSlices = params.listSlices();
SelectedFrames selFrames; SelectedFrames selFrames;
Tag* tag = calculate_selected_frames(site, tagName, selFrames); Tag* tag = calculate_selected_frames(site, tagName, selFrames);
frame_t nframes = selFrames.size(); frame_t nframes = selFrames.size();
ASSERT(nframes > 0); ASSERT(nframes > 0);
Doc* doc = const_cast<Doc*>(site.document());
const Sprite* sprite = site.sprite(); const Sprite* sprite = site.sprite();
// If the user choose to render selected layers only, we can // If the user choose to render selected layers only, we can
@ -249,8 +251,48 @@ void update_doc_exporter_from_params(const Site& site,
} }
} }
int nlayers = 0;
if (splitLayers) {
if (!selLayers.empty()) {
for (auto layer : selLayers.toAllLayersList()) {
if (layer->isGroup())
continue;
SelectedLayers oneLayer;
oneLayer.insert(layer);
exporter.addDocument(doc, tag, &oneLayer,
(!selFrames.empty() ? &selFrames: nullptr));
++nlayers;
}
}
else {
for (auto layer : sprite->allVisibleLayers()) {
if (layer->isGroup())
continue;
SelectedLayers oneLayer;
oneLayer.insert(layer);
exporter.addDocument(doc, tag, &oneLayer,
(!selFrames.empty() ? &selFrames: nullptr));
++nlayers;
}
}
}
else {
exporter.addDocument(doc, tag,
(!selLayers.empty() ? &selLayers: nullptr),
(!selFrames.empty() ? &selFrames: nullptr));
++nlayers;
}
nlayers = std::max(1, nlayers);
if (bestFit) { if (bestFit) {
Fit fit = best_fit(sprite, nframes, borderPadding, shapePadding, Fit fit = best_fit(sprite,
nframes * nlayers,
borderPadding,
shapePadding,
innerPadding + extrudePadding, innerPadding + extrudePadding,
type); type);
columns = fit.columns; columns = fit.columns;
@ -303,9 +345,6 @@ void update_doc_exporter_from_params(const Site& site,
if (listLayers) exporter.setListLayers(true); if (listLayers) exporter.setListLayers(true);
if (listTags) exporter.setListTags(true); if (listTags) exporter.setListTags(true);
if (listSlices) exporter.setListSlices(true); if (listSlices) exporter.setListSlices(true);
exporter.addDocument(const_cast<Doc*>(site.document()), tag,
(!selLayers.empty() ? &selLayers: nullptr),
(!selFrames.empty() ? &selFrames: nullptr));
} }
#if ENABLE_UI #if ENABLE_UI
@ -377,6 +416,7 @@ public:
m_dataFilename = params.dataFilename(); m_dataFilename = params.dataFilename();
dataEnabled()->setSelected(!m_dataFilename.empty()); dataEnabled()->setSelected(!m_dataFilename.empty());
dataFormat()->setSelectedItemIndex(int(params.dataFormat())); dataFormat()->setSelectedItemIndex(int(params.dataFormat()));
splitLayers()->setSelected(params.splitLayers());
listLayers()->setSelected(params.listLayers()); listLayers()->setSelected(params.listLayers());
listTags()->setSelected(params.listTags()); listTags()->setSelected(params.listTags());
listSlices()->setSelected(params.listSlices()); listSlices()->setSelected(params.listSlices());
@ -416,6 +456,8 @@ public:
dataFilename()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onDataFilename, this)); dataFilename()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onDataFilename, this));
trimEnabled()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onTrimEnabledChange, this)); trimEnabled()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onTrimEnabledChange, this));
paddingEnabled()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onPaddingEnabledChange, this)); paddingEnabled()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onPaddingEnabledChange, this));
layers()->Change.connect(base::Bind<void>(&ExportSpriteSheetWindow::onLayersChange, this));
splitLayers()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onLayersChange, this));
frames()->Change.connect(base::Bind<void>(&ExportSpriteSheetWindow::onFramesChange, this)); frames()->Change.connect(base::Bind<void>(&ExportSpriteSheetWindow::onFramesChange, this));
openGenerated()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onOpenGeneratedChange, this)); openGenerated()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onOpenGeneratedChange, this));
@ -447,6 +489,7 @@ public:
params.openGenerated (openGeneratedValue()); params.openGenerated (openGeneratedValue());
params.layer (layerValue()); params.layer (layerValue());
params.tag (tagValue()); params.tag (tagValue());
params.splitLayers (splitLayersValue());
params.listLayers (listLayersValue()); params.listLayers (listLayersValue());
params.listTags (listTagsValue()); params.listTags (listTagsValue());
params.listSlices (listSlicesValue()); params.listSlices (listSlicesValue());
@ -560,6 +603,10 @@ private:
return frames()->getValue(); return frames()->getValue();
} }
bool splitLayersValue() const {
return splitLayers()->isSelected();
}
bool listLayersValue() const { bool listLayersValue() const {
return listLayers()->isSelected(); return listLayers()->isSelected();
} }
@ -595,25 +642,8 @@ private:
break; break;
} }
// We have to detect if bestFit is selected, because the exchange // Recalculate cols/rows/fitWidth/Height fields
// "rows to columns" and "columns to rows" in this mode needs to recalculate updateSizeFields();
// these numbers.
// . NON best_fit method: only we have to show the hiden column or row value.
// . best_fit method: we have to recalculate the columns and rows.
if (matrixState && bestFitValue()) {
SelectedFrames selFrames;
calculate_selected_frames(m_site, tagValue(), selFrames);
frame_t nframes = selFrames.size();
Fit fit = best_fit(m_site.sprite(),
nframes,
borderPaddingValue(),
shapePaddingValue(),
innerPaddingValue() + extrudeValue(),
spriteSheetTypeValue());
rows()->setTextf("%d", fit.rows);
columns()->setTextf("%d", fit.columns);
}
columnsLabel()->setVisible(colsState); columnsLabel()->setVisible(colsState);
columns()->setVisible(colsState); columns()->setVisible(colsState);
@ -650,31 +680,28 @@ private:
void onSizeChange() { void onSizeChange() {
SelectedFrames selFrames; SelectedFrames selFrames;
calculate_selected_frames(m_site, tagValue(), selFrames); calculate_selected_frames(m_site, tagValue(), selFrames);
frame_t nframes = selFrames.size(); const frame_t nframes = selFrames.size();
int borderPadding = 0; const int nlayers = calculateNLayers();
int innerPadding = 0; const int borderPadding = borderPaddingValue();
int shapePadding = 0; const int innerPadding = innerPaddingValue() + extrudeValue();
if (paddingEnabled()->isEnabled()) { const int shapePadding = shapePaddingValue();
borderPadding = borderPaddingValue(); const int framew = m_sprite->width() + 2*innerPadding + shapePadding;
innerPadding = innerPaddingValue() + extrudeValue(); const int frameh = m_sprite->height() + 2*innerPadding + shapePadding;
shapePadding = shapePaddingValue(); const int w = fitWidthValue() - 2*borderPadding + shapePadding;
} const int h = fitHeightValue() - 2*borderPadding + shapePadding;
int framew = m_sprite->width() + 2*innerPadding + shapePadding; const int nsamples = nframes * nlayers;
int frameh = m_sprite->height() + 2*innerPadding + shapePadding; int rows;
int w = fitWidthValue() - 2*borderPadding + shapePadding; int cols;
int h = fitHeightValue() - 2*borderPadding + shapePadding;
int r;// rows
int c;// columns
if (spriteSheetTypeValue() == SpriteSheetType::Columns) { if (spriteSheetTypeValue() == SpriteSheetType::Columns) {
r = base::clamp(h / frameh, 1, nframes); rows = base::clamp(h / frameh, 1, nsamples);
c = nframes / r + (nframes % r? 1 : 0); cols = (nsamples / rows) + (nsamples % rows ? 1 : 0);
} }
else { else {
c = base::clamp(w / framew, 1, nframes); cols = base::clamp(w / framew, 1, nsamples);
r = nframes / c + (nframes % c? 1 : 0); rows = (nsamples / cols) + (nsamples % cols ? 1 : 0);
} }
columns()->setTextf("%d", c); this->columns()->setTextf("%d", cols);
rows()->setTextf("%d", r); this->rows()->setTextf("%d", rows);
bestFit()->setSelected(false); bestFit()->setSelected(false);
} }
@ -730,9 +757,9 @@ private:
} }
void onTrimEnabledChange() { void onTrimEnabledChange() {
trimContainer()->setVisible(trimEnabled()->isSelected()); trimContainer()->setVisible(trimEnabled()->isSelected());
resize(); resize();
updateSizeFields(); updateSizeFields();
} }
void onPaddingEnabledChange() { void onPaddingEnabledChange() {
@ -749,6 +776,10 @@ private:
updateSizeFields(); updateSizeFields();
} }
void onLayersChange() {
updateSizeFields();
}
void onFramesChange() { void onFramesChange() {
updateSizeFields(); updateSizeFields();
} }
@ -777,18 +808,20 @@ private:
tagValue(), tagValue(),
selFrames); selFrames);
frame_t nframes = selFrames.size(); const frame_t nframes = selFrames.size();
const int nlayers = calculateNLayers();
Fit fit; Fit fit;
if (bestFit()->isSelected()) { if (bestFit()->isSelected()) {
fit = best_fit(m_sprite, nframes, fit = best_fit(m_sprite,
nframes * nlayers,
borderPaddingValue(), shapePaddingValue(), borderPaddingValue(), shapePaddingValue(),
innerPaddingValue() + extrudePadding(), innerPaddingValue() + extrudePadding(),
spriteSheetTypeValue()); spriteSheetTypeValue());
} }
else { else {
fit = calculate_sheet_size( fit = calculate_sheet_size(
m_sprite, nframes, m_sprite, nframes * nlayers,
columnsValue(), columnsValue(),
rowsValue(), rowsValue(),
borderPaddingValue(), borderPaddingValue(),
@ -808,6 +841,48 @@ private:
dataMeta()->setVisible(state); dataMeta()->setVisible(state);
} }
int calculateNLayers() {
const std::string layerName = layerValue();
RestoreVisibleLayers layersVisibility;
calculate_visible_layers(m_site, layerName, layersVisibility);
// TODO similar to the code in update_doc_exporter_from_params()
int nlayers = 0;
if (splitLayersValue()) {
SelectedLayers selLayers;
if (layerName != kSelectedLayers) {
for (const Layer* layer : m_sprite->allLayers()) {
if (layer->name() == layerName) {
selLayers.insert(const_cast<Layer*>(layer));
break;
}
}
}
if (!selLayers.empty()) {
for (auto layer : selLayers.toAllLayersList()) {
if (layer->isGroup())
continue;
++nlayers;
}
}
else {
for (auto layer : m_sprite->allVisibleLayers()) {
if (layer->isGroup())
continue;
++nlayers;
}
}
}
else {
++nlayers;
}
return std::max(1, nlayers);
}
Site& m_site; Site& m_site;
Sprite* m_sprite; Sprite* m_sprite;
std::string m_filename; std::string m_filename;
@ -880,6 +955,7 @@ void ExportSpriteSheetCommand::onExecute(Context* context)
if (!params.openGenerated.isSet()) params.openGenerated( docPref.spriteSheet.openGenerated()); if (!params.openGenerated.isSet()) params.openGenerated( docPref.spriteSheet.openGenerated());
if (!params.layer.isSet()) params.layer( docPref.spriteSheet.layer()); if (!params.layer.isSet()) params.layer( docPref.spriteSheet.layer());
if (!params.tag.isSet()) params.tag( docPref.spriteSheet.frameTag()); if (!params.tag.isSet()) params.tag( docPref.spriteSheet.frameTag());
if (!params.splitLayers.isSet()) params.splitLayers( docPref.spriteSheet.splitLayers());
if (!params.listLayers.isSet()) params.listLayers( docPref.spriteSheet.listLayers()); if (!params.listLayers.isSet()) params.listLayers( docPref.spriteSheet.listLayers());
if (!params.listTags.isSet()) params.listTags( docPref.spriteSheet.listFrameTags()); if (!params.listTags.isSet()) params.listTags( docPref.spriteSheet.listFrameTags());
if (!params.listSlices.isSet()) params.listSlices( docPref.spriteSheet.listSlices()); if (!params.listSlices.isSet()) params.listSlices( docPref.spriteSheet.listSlices());
@ -912,6 +988,7 @@ void ExportSpriteSheetCommand::onExecute(Context* context)
docPref.spriteSheet.openGenerated (params.openGenerated()); docPref.spriteSheet.openGenerated (params.openGenerated());
docPref.spriteSheet.layer (params.layer()); docPref.spriteSheet.layer (params.layer());
docPref.spriteSheet.frameTag (params.tag()); docPref.spriteSheet.frameTag (params.tag());
docPref.spriteSheet.splitLayers (params.splitLayers());
docPref.spriteSheet.listLayers (params.listLayers()); docPref.spriteSheet.listLayers (params.listLayers());
docPref.spriteSheet.listFrameTags (params.listTags()); docPref.spriteSheet.listFrameTags (params.listTags());
docPref.spriteSheet.listSlices (params.listSlices()); docPref.spriteSheet.listSlices (params.listSlices());