mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-02 13:14:01 +00:00
Add "File > Export > Export Tileset" option (#3240)
Now we can export one (or several) tilesets in one sprite sheet (using the same options that are available in the Export Sprite Sheet dialog, e.g. like extruding tiles, related to #1982 in some way). Some changes: * New "Source" field and fromTilesets param for ExportSpriteSheet command * New ExportTileset command (which acts like ExportSpriteSheet but with fromTilesets=true by default) * Added --export-tileset CLI option
This commit is contained in:
parent
bdee7d98fe
commit
a2f61a3378
11
data/gui.xml
11
data/gui.xml
@ -455,6 +455,9 @@
|
|||||||
<key command="NewSpriteFromSelection" shortcut="Ctrl+Alt+N" mac="Cmd+Alt+N" />
|
<key command="NewSpriteFromSelection" shortcut="Ctrl+Alt+N" mac="Cmd+Alt+N" />
|
||||||
|
|
||||||
<!-- Commands not associated to menu items and without shortcuts by default -->
|
<!-- Commands not associated to menu items and without shortcuts by default -->
|
||||||
|
<key command="ExportSpriteSheet">
|
||||||
|
<param name="source" value="tileset" />
|
||||||
|
</key>
|
||||||
<key command="NewLayer">
|
<key command="NewLayer">
|
||||||
<param name="tilemap" value="true" />
|
<param name="tilemap" value="true" />
|
||||||
</key>
|
</key>
|
||||||
@ -675,12 +678,14 @@
|
|||||||
<separator />
|
<separator />
|
||||||
<menu text="@.file_export" group="file_export">
|
<menu text="@.file_export" group="file_export">
|
||||||
<item command="SaveFileCopyAs" text="@.file_export_as" />
|
<item command="SaveFileCopyAs" text="@.file_export_as" />
|
||||||
<item command="ExportSpriteSheet" text="@.file_export_sprite_sheet" group="file_export_sub" />
|
<item command="ExportSpriteSheet" text="@.file_export_sprite_sheet" group="file_export_1" />
|
||||||
<separator />
|
<separator />
|
||||||
<item command="RepeatLastExport" text="@.file_repeat_last_export" />
|
<item command="ExportTileset" text="@.file_export_tileset" group="file_export_2" />
|
||||||
|
<separator />
|
||||||
|
<item command="RepeatLastExport" text="@.file_repeat_last_export" group="file_export_last" />
|
||||||
</menu>
|
</menu>
|
||||||
<menu text="@.file_import" group="file_import">
|
<menu text="@.file_import" group="file_import">
|
||||||
<item command="ImportSpriteSheet" text="@.file_import_sprite_sheet" group="file_import_sub" />
|
<item command="ImportSpriteSheet" text="@.file_import_sprite_sheet" group="file_import_1" />
|
||||||
</menu>
|
</menu>
|
||||||
<separator id="scripts_menu_separator" />
|
<separator id="scripts_menu_separator" />
|
||||||
<menu id="scripts_menu" text="@.file_scripts" group="file_scripts">
|
<menu id="scripts_menu" text="@.file_scripts" group="file_scripts">
|
||||||
|
@ -307,6 +307,7 @@ DuplicateSprite = Duplicate Sprite
|
|||||||
DuplicateView = Duplicate View
|
DuplicateView = Duplicate View
|
||||||
Exit = Exit
|
Exit = Exit
|
||||||
ExportSpriteSheet = Export Sprite Sheet
|
ExportSpriteSheet = Export Sprite Sheet
|
||||||
|
ExportTileset = Export Tileset
|
||||||
Eyedropper = Eyedropper
|
Eyedropper = Eyedropper
|
||||||
Fill = Fill Selection with Foreground Color
|
Fill = Fill Selection with Foreground Color
|
||||||
FitScreen = Fit on Screen
|
FitScreen = Fit on Screen
|
||||||
@ -706,6 +707,7 @@ merge_dups = Merge Duplicates
|
|||||||
merge_dups_tooltip = Similar frames can use the same sprite sheet rectangular area
|
merge_dups_tooltip = Similar frames can use the same sprite sheet rectangular area
|
||||||
ignore_empty = Ignore Empty
|
ignore_empty = Ignore Empty
|
||||||
ignore_empty_tooltip = Do not include empty/transparent frames in the sprite sheet
|
ignore_empty_tooltip = Do not include empty/transparent frames in the sprite sheet
|
||||||
|
source = Source:
|
||||||
layers = Layers:
|
layers = Layers:
|
||||||
split_layers = Split Layers
|
split_layers = Split Layers
|
||||||
split_layers_tooltip = Generates one sprite for each layer
|
split_layers_tooltip = Generates one sprite for each layer
|
||||||
@ -891,6 +893,7 @@ file_close_all = Close All
|
|||||||
file_export = &Export
|
file_export = &Export
|
||||||
file_export_as = &Export As...
|
file_export_as = &Export As...
|
||||||
file_export_sprite_sheet = Export &Sprite Sheet
|
file_export_sprite_sheet = Export &Sprite Sheet
|
||||||
|
file_export_tileset = Export &Tileset
|
||||||
file_repeat_last_export = Repeat &Last Export
|
file_repeat_last_export = Repeat &Last Export
|
||||||
file_import = &Import
|
file_import = &Import
|
||||||
file_import_sprite_sheet = &Import Sprite Sheet
|
file_import_sprite_sheet = &Import Sprite Sheet
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!-- Aseprite -->
|
<!-- Aseprite -->
|
||||||
<!-- Copyright (C) 2019 Igara Studio S.A. -->
|
<!-- Copyright (C) 2019-2022 Igara Studio S.A. -->
|
||||||
<!-- Copyright (C) 2001-2018 David Capello -->
|
<!-- Copyright (C) 2001-2018 David Capello -->
|
||||||
<gui>
|
<gui>
|
||||||
<window id="export_sprite_sheet" text="@.title">
|
<window id="export_sprite_sheet" text="@.title">
|
||||||
@ -50,6 +50,10 @@
|
|||||||
<button id="close_sprite_section" icon="window_close_icon" />
|
<button id="close_sprite_section" icon="window_close_icon" />
|
||||||
</hbox>
|
</hbox>
|
||||||
<grid id="section_sprite" columns="4" expansive="true">
|
<grid id="section_sprite" columns="4" expansive="true">
|
||||||
|
<label text="@.source" />
|
||||||
|
<combobox id="source" text="" cell_hspan="2" cell_align="horizontal" />
|
||||||
|
<boxfiller />
|
||||||
|
|
||||||
<label text="@.layers" />
|
<label text="@.layers" />
|
||||||
<combobox id="layers" text="" cell_hspan="2" cell_align="horizontal" />
|
<combobox id="layers" text="" cell_hspan="2" cell_align="horizontal" />
|
||||||
<check id="split_layers" text="@.split_layers" tooltip="@.split_layers_tooltip" tooltip_dir="bottom" />
|
<check id="split_layers" text="@.split_layers" tooltip="@.split_layers_tooltip" tooltip_dir="bottom" />
|
||||||
|
@ -570,6 +570,7 @@ add_library(app-lib
|
|||||||
commands/command.cpp
|
commands/command.cpp
|
||||||
commands/commands.cpp
|
commands/commands.cpp
|
||||||
commands/convert_layer.cpp
|
commands/convert_layer.cpp
|
||||||
|
commands/export_tileset.cpp
|
||||||
commands/filters/cmd_brightness_contrast.cpp
|
commands/filters/cmd_brightness_contrast.cpp
|
||||||
commands/filters/cmd_color_curve.cpp
|
commands/filters/cmd_color_curve.cpp
|
||||||
commands/filters/cmd_convolution_matrix.cpp
|
commands/filters/cmd_convolution_matrix.cpp
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2019 Igara Studio S.A.
|
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2017 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -73,6 +73,7 @@ AppOptions::AppOptions(int argc, const char* argv[])
|
|||||||
, m_listTags(m_po.add("list-tags").description("List tags of the next given sprite\nor include frame tags in JSON data"))
|
, m_listTags(m_po.add("list-tags").description("List tags of the next given sprite\nor include frame tags in JSON data"))
|
||||||
, m_listSlices(m_po.add("list-slices").description("List slices of the next given sprite\nor include slices in JSON data"))
|
, m_listSlices(m_po.add("list-slices").description("List slices of the next given sprite\nor include slices in JSON data"))
|
||||||
, m_oneFrame(m_po.add("oneframe").description("Load just the first frame"))
|
, m_oneFrame(m_po.add("oneframe").description("Load just the first frame"))
|
||||||
|
, m_exportTileset(m_po.add("export-tileset").description("Export only tilesets from visible tilemap layers"))
|
||||||
, m_verbose(m_po.add("verbose").mnemonic('v').description("Explain what is being done"))
|
, m_verbose(m_po.add("verbose").mnemonic('v').description("Explain what is being done"))
|
||||||
, m_debug(m_po.add("debug").description("Extreme verbose mode and\ncopy log to desktop"))
|
, m_debug(m_po.add("debug").description("Extreme verbose mode and\ncopy log to desktop"))
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2019 Igara Studio S.A.
|
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2017 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -89,6 +89,7 @@ public:
|
|||||||
const Option& listTags() const { return m_listTags; }
|
const Option& listTags() const { return m_listTags; }
|
||||||
const Option& listSlices() const { return m_listSlices; }
|
const Option& listSlices() const { return m_listSlices; }
|
||||||
const Option& oneFrame() const { return m_oneFrame; }
|
const Option& oneFrame() const { return m_oneFrame; }
|
||||||
|
const Option& exportTileset() const { return m_exportTileset; }
|
||||||
|
|
||||||
bool hasExporterParams() const;
|
bool hasExporterParams() const;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -155,6 +156,7 @@ private:
|
|||||||
Option& m_listTags;
|
Option& m_listTags;
|
||||||
Option& m_listSlices;
|
Option& m_listSlices;
|
||||||
Option& m_oneFrame;
|
Option& m_oneFrame;
|
||||||
|
Option& m_exportTileset;
|
||||||
|
|
||||||
Option& m_verbose;
|
Option& m_verbose;
|
||||||
Option& m_debug;
|
Option& m_debug;
|
||||||
|
@ -19,25 +19,6 @@
|
|||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
CliOpenFile::CliOpenFile()
|
|
||||||
{
|
|
||||||
document = nullptr;
|
|
||||||
fromFrame = -1;
|
|
||||||
toFrame = -1;
|
|
||||||
splitLayers = false;
|
|
||||||
splitTags = false;
|
|
||||||
splitSlices = false;
|
|
||||||
allLayers = false;
|
|
||||||
listLayers = false;
|
|
||||||
listTags = false;
|
|
||||||
listSlices = false;
|
|
||||||
ignoreEmpty = false;
|
|
||||||
trim = false;
|
|
||||||
trimByGrid = false;
|
|
||||||
oneFrame = false;
|
|
||||||
crop = gfx::Rect();
|
|
||||||
}
|
|
||||||
|
|
||||||
FileOpROI CliOpenFile::roi() const
|
FileOpROI CliOpenFile::roi() const
|
||||||
{
|
{
|
||||||
ASSERT(document);
|
ASSERT(document);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2019 Igara Studio S.A.
|
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2016-2017 David Capello
|
// Copyright (C) 2016-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -21,29 +21,29 @@ namespace app {
|
|||||||
class FileOpROI;
|
class FileOpROI;
|
||||||
|
|
||||||
struct CliOpenFile {
|
struct CliOpenFile {
|
||||||
Doc* document;
|
Doc* document = nullptr;
|
||||||
std::string filename;
|
std::string filename;
|
||||||
std::string filenameFormat;
|
std::string filenameFormat;
|
||||||
std::string tag;
|
std::string tag;
|
||||||
std::string slice;
|
std::string slice;
|
||||||
std::vector<std::string> includeLayers;
|
std::vector<std::string> includeLayers;
|
||||||
std::vector<std::string> excludeLayers;
|
std::vector<std::string> excludeLayers;
|
||||||
doc::frame_t fromFrame, toFrame;
|
doc::frame_t fromFrame = -1;
|
||||||
bool splitLayers;
|
doc::frame_t toFrame = -1;
|
||||||
bool splitTags;
|
bool splitLayers = false;
|
||||||
bool splitSlices;
|
bool splitTags = false;
|
||||||
bool allLayers;
|
bool splitSlices = false;
|
||||||
bool listLayers;
|
bool allLayers = false;
|
||||||
bool listTags;
|
bool listLayers = false;
|
||||||
bool listSlices;
|
bool listTags = false;
|
||||||
bool ignoreEmpty;
|
bool listSlices = false;
|
||||||
bool trim;
|
bool ignoreEmpty = false;
|
||||||
bool trimByGrid;
|
bool trim = false;
|
||||||
bool oneFrame;
|
bool trimByGrid = false;
|
||||||
|
bool oneFrame = false;
|
||||||
|
bool exportTileset = false;
|
||||||
gfx::Rect crop;
|
gfx::Rect crop;
|
||||||
|
|
||||||
CliOpenFile();
|
|
||||||
|
|
||||||
bool hasTag() const {
|
bool hasTag() const {
|
||||||
return (!tag.empty());
|
return (!tag.empty());
|
||||||
}
|
}
|
||||||
|
@ -578,6 +578,10 @@ int CliProcessor::process(Context* ctx)
|
|||||||
else if (opt == &m_options.oneFrame()) {
|
else if (opt == &m_options.oneFrame()) {
|
||||||
cof.oneFrame = true;
|
cof.oneFrame = true;
|
||||||
}
|
}
|
||||||
|
// --export-tileset
|
||||||
|
else if (opt == &m_options.exportTileset()) {
|
||||||
|
cof.exportTileset = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// File names aren't associated to any option
|
// File names aren't associated to any option
|
||||||
else {
|
else {
|
||||||
@ -677,12 +681,19 @@ bool CliProcessor::openFile(Context* ctx, CliOpenFile& cof)
|
|||||||
if (cof.hasLayersFilter())
|
if (cof.hasLayersFilter())
|
||||||
filterLayers(doc->sprite(), cof, filteredLayers);
|
filterLayers(doc->sprite(), cof, filteredLayers);
|
||||||
|
|
||||||
m_exporter->addDocumentSamples(
|
if (cof.exportTileset) {
|
||||||
doc, tag,
|
m_exporter->addTilesetsSamples(
|
||||||
cof.splitLayers,
|
doc,
|
||||||
cof.splitTags,
|
(cof.hasLayersFilter() ? &filteredLayers: nullptr));
|
||||||
(cof.hasLayersFilter() ? &filteredLayers: nullptr),
|
}
|
||||||
(!selFrames.empty() ? &selFrames: nullptr));
|
else {
|
||||||
|
m_exporter->addDocumentSamples(
|
||||||
|
doc, tag,
|
||||||
|
cof.splitLayers,
|
||||||
|
cof.splitTags,
|
||||||
|
(cof.hasLayersFilter() ? &filteredLayers: nullptr),
|
||||||
|
(!selFrames.empty() ? &selFrames: nullptr));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "app/app.h"
|
#include "app/app.h"
|
||||||
#include "app/commands/new_params.h"
|
#include "app/commands/cmd_export_sprite_sheet.h"
|
||||||
#include "app/context.h"
|
#include "app/context.h"
|
||||||
#include "app/context_access.h"
|
#include "app/context_access.h"
|
||||||
#include "app/doc.h"
|
#include "app/doc.h"
|
||||||
@ -37,7 +37,10 @@
|
|||||||
#include "base/string.h"
|
#include "base/string.h"
|
||||||
#include "base/thread.h"
|
#include "base/thread.h"
|
||||||
#include "doc/layer.h"
|
#include "doc/layer.h"
|
||||||
|
#include "doc/layer_tilemap.h"
|
||||||
#include "doc/tag.h"
|
#include "doc/tag.h"
|
||||||
|
#include "doc/tileset.h"
|
||||||
|
#include "doc/tilesets.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "ui/message.h"
|
#include "ui/message.h"
|
||||||
#include "ui/system.h"
|
#include "ui/system.h"
|
||||||
@ -53,37 +56,6 @@ using namespace ui;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct ExportSpriteSheetParams : public NewParams {
|
|
||||||
Param<bool> ui { this, true, "ui" };
|
|
||||||
Param<bool> askOverwrite { this, true, { "askOverwrite", "ask-overwrite" } };
|
|
||||||
Param<app::SpriteSheetType> type { this, app::SpriteSheetType::None, "type" };
|
|
||||||
Param<int> columns { this, 0, "columns" };
|
|
||||||
Param<int> rows { this, 0, "rows" };
|
|
||||||
Param<int> width { this, 0, "width" };
|
|
||||||
Param<int> height { this, 0, "height" };
|
|
||||||
Param<std::string> textureFilename { this, std::string(), "textureFilename" };
|
|
||||||
Param<std::string> dataFilename { this, std::string(), "dataFilename" };
|
|
||||||
Param<SpriteSheetDataFormat> dataFormat { this, SpriteSheetDataFormat::Default, "dataFormat" };
|
|
||||||
Param<std::string> filenameFormat { this, std::string(), "filenameFormat" };
|
|
||||||
Param<int> borderPadding { this, 0, "borderPadding" };
|
|
||||||
Param<int> shapePadding { this, 0, "shapePadding" };
|
|
||||||
Param<int> innerPadding { this, 0, "innerPadding" };
|
|
||||||
Param<bool> trimSprite { this, false, "trimSprite" };
|
|
||||||
Param<bool> trim { this, false, "trim" };
|
|
||||||
Param<bool> trimByGrid { this, false, "trimByGrid" };
|
|
||||||
Param<bool> extrude { this, false, "extrude" };
|
|
||||||
Param<bool> ignoreEmpty { this, false, "ignoreEmpty" };
|
|
||||||
Param<bool> mergeDuplicates { this, false, "mergeDuplicates" };
|
|
||||||
Param<bool> openGenerated { this, false, "openGenerated" };
|
|
||||||
Param<std::string> layer { this, std::string(), "layer" };
|
|
||||||
Param<std::string> tag { this, std::string(), "tag" };
|
|
||||||
Param<bool> splitLayers { this, false, "splitLayers" };
|
|
||||||
Param<bool> splitTags { this, false, "splitTags" };
|
|
||||||
Param<bool> listLayers { this, true, "listLayers" };
|
|
||||||
Param<bool> listTags { this, true, "listTags" };
|
|
||||||
Param<bool> listSlices { this, true, "listSlices" };
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef ENABLE_UI
|
#ifdef ENABLE_UI
|
||||||
|
|
||||||
enum Section {
|
enum Section {
|
||||||
@ -93,6 +65,11 @@ enum Section {
|
|||||||
kSectionOutput,
|
kSectionOutput,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum Source {
|
||||||
|
kSource_Sprite,
|
||||||
|
kSource_Tilesets,
|
||||||
|
};
|
||||||
|
|
||||||
enum ConstraintType {
|
enum ConstraintType {
|
||||||
kConstraintType_None,
|
kConstraintType_None,
|
||||||
kConstraintType_Cols,
|
kConstraintType_Cols,
|
||||||
@ -197,6 +174,7 @@ Doc* generate_sprite_sheet_from_params(
|
|||||||
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();
|
||||||
|
const bool fromTilesets = params.fromTilesets();
|
||||||
|
|
||||||
SelectedFrames selFrames;
|
SelectedFrames selFrames;
|
||||||
Tag* tag = calculate_selected_frames(site, tagName, selFrames);
|
Tag* tag = calculate_selected_frames(site, tagName, selFrames);
|
||||||
@ -226,10 +204,16 @@ Doc* generate_sprite_sheet_from_params(
|
|||||||
}
|
}
|
||||||
|
|
||||||
exporter.reset();
|
exporter.reset();
|
||||||
exporter.addDocumentSamples(
|
if (fromTilesets)
|
||||||
doc, tag, splitLayers, splitTags,
|
exporter.addTilesetsSamples(
|
||||||
!selLayers.empty() ? &selLayers: nullptr,
|
doc,
|
||||||
!selFrames.empty() ? &selFrames: nullptr);
|
!selLayers.empty() ? &selLayers: nullptr);
|
||||||
|
else {
|
||||||
|
exporter.addDocumentSamples(
|
||||||
|
doc, tag, splitLayers, splitTags,
|
||||||
|
!selLayers.empty() ? &selLayers: nullptr,
|
||||||
|
!selFrames.empty() ? &selFrames: nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
if (saveData) {
|
if (saveData) {
|
||||||
if (!filename.empty())
|
if (!filename.empty())
|
||||||
@ -373,6 +357,14 @@ public:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static_assert(kSource_Sprite == 0 &&
|
||||||
|
kSource_Tilesets == 1,
|
||||||
|
"Source enum has changed");
|
||||||
|
source()->addItem(new ListItem("Sprite"));
|
||||||
|
source()->addItem(new ListItem("Tilesets"));
|
||||||
|
if (params.fromTilesets())
|
||||||
|
source()->setSelectedItemIndex(int(kSource_Tilesets));
|
||||||
|
|
||||||
fill_layers_combobox(
|
fill_layers_combobox(
|
||||||
m_sprite, layers(), params.layer());
|
m_sprite, layers(), params.layer());
|
||||||
|
|
||||||
@ -446,6 +438,7 @@ public:
|
|||||||
trimSpriteEnabled()->Click.connect([this]{ onTrimEnabledChange(); });
|
trimSpriteEnabled()->Click.connect([this]{ onTrimEnabledChange(); });
|
||||||
trimEnabled()->Click.connect([this]{ onTrimEnabledChange(); });
|
trimEnabled()->Click.connect([this]{ onTrimEnabledChange(); });
|
||||||
gridTrimEnabled()->Click.connect([this]{ generatePreview(); });
|
gridTrimEnabled()->Click.connect([this]{ generatePreview(); });
|
||||||
|
source()->Change.connect([this]{ generatePreview(); });
|
||||||
layers()->Change.connect([this]{ generatePreview(); });
|
layers()->Change.connect([this]{ generatePreview(); });
|
||||||
splitLayers()->Click.connect([this]{ onSplitLayersOrFrames(); });
|
splitLayers()->Click.connect([this]{ onSplitLayersOrFrames(); });
|
||||||
splitTags()->Click.connect([this]{ onSplitLayersOrFrames(); });
|
splitTags()->Click.connect([this]{ onSplitLayersOrFrames(); });
|
||||||
@ -536,6 +529,7 @@ public:
|
|||||||
params.listLayers (listLayersValue());
|
params.listLayers (listLayersValue());
|
||||||
params.listTags (listTagsValue());
|
params.listTags (listTagsValue());
|
||||||
params.listSlices (listSlicesValue());
|
params.listSlices (listSlicesValue());
|
||||||
|
params.fromTilesets (source()->getSelectedItemIndex() == int(kSource_Tilesets));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -1169,16 +1163,8 @@ private:
|
|||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
class ExportSpriteSheetCommand : public CommandWithNewParams<ExportSpriteSheetParams> {
|
ExportSpriteSheetCommand::ExportSpriteSheetCommand(const char* id)
|
||||||
public:
|
: CommandWithNewParams(id, CmdRecordableFlag)
|
||||||
ExportSpriteSheetCommand();
|
|
||||||
protected:
|
|
||||||
bool onEnabled(Context* context) override;
|
|
||||||
void onExecute(Context* context) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
ExportSpriteSheetCommand::ExportSpriteSheetCommand()
|
|
||||||
: CommandWithNewParams(CommandId::ExportSpriteSheet(), CmdRecordableFlag)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
62
src/app/commands/cmd_export_sprite_sheet.h
Normal file
62
src/app/commands/cmd_export_sprite_sheet.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2022 Igara Studio S.A.
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifndef APP_COMMANDS_CMD_EXPORT_SPRITE_SHEET_H_INCLUDED
|
||||||
|
#define APP_COMMANDS_CMD_EXPORT_SPRITE_SHEET_H_INCLUDED
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "app/commands/new_params.h"
|
||||||
|
#include "app/sprite_sheet_data_format.h"
|
||||||
|
#include "app/sprite_sheet_type.h"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
struct ExportSpriteSheetParams : public NewParams {
|
||||||
|
Param<bool> ui { this, true, "ui" };
|
||||||
|
Param<bool> askOverwrite { this, true, { "askOverwrite", "ask-overwrite" } };
|
||||||
|
Param<app::SpriteSheetType> type { this, app::SpriteSheetType::None, "type" };
|
||||||
|
Param<int> columns { this, 0, "columns" };
|
||||||
|
Param<int> rows { this, 0, "rows" };
|
||||||
|
Param<int> width { this, 0, "width" };
|
||||||
|
Param<int> height { this, 0, "height" };
|
||||||
|
Param<std::string> textureFilename { this, std::string(), "textureFilename" };
|
||||||
|
Param<std::string> dataFilename { this, std::string(), "dataFilename" };
|
||||||
|
Param<SpriteSheetDataFormat> dataFormat { this, SpriteSheetDataFormat::Default, "dataFormat" };
|
||||||
|
Param<std::string> filenameFormat { this, std::string(), "filenameFormat" };
|
||||||
|
Param<int> borderPadding { this, 0, "borderPadding" };
|
||||||
|
Param<int> shapePadding { this, 0, "shapePadding" };
|
||||||
|
Param<int> innerPadding { this, 0, "innerPadding" };
|
||||||
|
Param<bool> trimSprite { this, false, "trimSprite" };
|
||||||
|
Param<bool> trim { this, false, "trim" };
|
||||||
|
Param<bool> trimByGrid { this, false, "trimByGrid" };
|
||||||
|
Param<bool> extrude { this, false, "extrude" };
|
||||||
|
Param<bool> ignoreEmpty { this, false, "ignoreEmpty" };
|
||||||
|
Param<bool> mergeDuplicates { this, false, "mergeDuplicates" };
|
||||||
|
Param<bool> openGenerated { this, false, "openGenerated" };
|
||||||
|
Param<std::string> layer { this, std::string(), "layer" };
|
||||||
|
Param<std::string> tag { this, std::string(), "tag" };
|
||||||
|
Param<bool> splitLayers { this, false, "splitLayers" };
|
||||||
|
Param<bool> splitTags { this, false, "splitTags" };
|
||||||
|
Param<bool> listLayers { this, true, "listLayers" };
|
||||||
|
Param<bool> listTags { this, true, "listTags" };
|
||||||
|
Param<bool> listSlices { this, true, "listSlices" };
|
||||||
|
Param<bool> fromTilesets { this, false, "fromTilesets" };
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExportSpriteSheetCommand : public CommandWithNewParams<ExportSpriteSheetParams> {
|
||||||
|
public:
|
||||||
|
ExportSpriteSheetCommand(const char* id = CommandId::ExportSpriteSheet());
|
||||||
|
protected:
|
||||||
|
bool onEnabled(Context* context) override;
|
||||||
|
void onExecute(Context* context) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace app
|
||||||
|
|
||||||
|
#endif // APP_COMMANDS_CMD_EXPORT_SPRITE_SHEET_H_INCLUDED
|
@ -21,6 +21,7 @@ FOR_EACH_COMMAND(CopyTiles)
|
|||||||
FOR_EACH_COMMAND(CropSprite)
|
FOR_EACH_COMMAND(CropSprite)
|
||||||
FOR_EACH_COMMAND(Despeckle)
|
FOR_EACH_COMMAND(Despeckle)
|
||||||
FOR_EACH_COMMAND(ExportSpriteSheet)
|
FOR_EACH_COMMAND(ExportSpriteSheet)
|
||||||
|
FOR_EACH_COMMAND(ExportTileset)
|
||||||
FOR_EACH_COMMAND(Fill)
|
FOR_EACH_COMMAND(Fill)
|
||||||
FOR_EACH_COMMAND(FlattenLayers)
|
FOR_EACH_COMMAND(FlattenLayers)
|
||||||
FOR_EACH_COMMAND(Flip)
|
FOR_EACH_COMMAND(Flip)
|
||||||
|
65
src/app/commands/export_tileset.cpp
Normal file
65
src/app/commands/export_tileset.cpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2022 Igara Studio S.A.
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "app/commands/cmd_export_sprite_sheet.h"
|
||||||
|
#include "app/commands/command_ids.h"
|
||||||
|
#include "app/context.h"
|
||||||
|
#include "app/site.h"
|
||||||
|
#include "app/ui/layer_frame_comboboxes.h"
|
||||||
|
#include "doc/layer.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
class ExportTilesetCommand : public ExportSpriteSheetCommand {
|
||||||
|
public:
|
||||||
|
ExportTilesetCommand();
|
||||||
|
protected:
|
||||||
|
void onResetValues() override;
|
||||||
|
bool onEnabled(Context* context) override;
|
||||||
|
void onExecute(Context* context) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
ExportTilesetCommand::ExportTilesetCommand()
|
||||||
|
: ExportSpriteSheetCommand(CommandId::ExportTileset())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExportTilesetCommand::onResetValues()
|
||||||
|
{
|
||||||
|
ExportSpriteSheetCommand::onResetValues();
|
||||||
|
|
||||||
|
// Default values for Export Tileset
|
||||||
|
params().fromTilesets(true);
|
||||||
|
params().layer(kSelectedLayers);
|
||||||
|
params().dataFormat(SpriteSheetDataFormat::JsonArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExportTilesetCommand::onEnabled(Context* ctx)
|
||||||
|
{
|
||||||
|
if (ExportSpriteSheetCommand::onEnabled(ctx) &&
|
||||||
|
ctx->checkFlags(ContextFlags::HasActiveLayer)) {
|
||||||
|
Site site = ctx->activeSite();
|
||||||
|
if (site.layer() && site.layer()->isTilemap())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExportTilesetCommand::onExecute(Context* ctx)
|
||||||
|
{
|
||||||
|
ExportSpriteSheetCommand::onExecute(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
Command* CommandFactory::createExportTilesetCommand()
|
||||||
|
{
|
||||||
|
return new ExportTilesetCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace app
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2019 Igara Studio S.A.
|
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
@ -139,7 +139,7 @@ namespace app {
|
|||||||
T& params() { return m_params; }
|
T& params() { return m_params; }
|
||||||
const T& params() const { return m_params; }
|
const T& params() const { return m_params; }
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
void onResetValues() override {
|
void onResetValues() override {
|
||||||
m_params.resetValues();
|
m_params.resetValues();
|
||||||
}
|
}
|
||||||
@ -148,6 +148,7 @@ namespace app {
|
|||||||
return m_params.getParam(k);
|
return m_params.getParam(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
T m_params;
|
T m_params;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -104,6 +104,13 @@ DocExporter::Item::Item(Doc* doc,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DocExporter::Item::Item(Doc* doc,
|
||||||
|
const doc::ImageRef& image)
|
||||||
|
: doc(doc)
|
||||||
|
, image(image)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
DocExporter::Item::Item(Item&& other) = default;
|
DocExporter::Item::Item(Item&& other) = default;
|
||||||
DocExporter::Item::~Item() = default;
|
DocExporter::Item::~Item() = default;
|
||||||
|
|
||||||
@ -129,6 +136,8 @@ doc::SelectedFrames DocExporter::Item::getSelectedFrames() const
|
|||||||
frames.insert(std::clamp(tag->fromFrame(), 0, doc->sprite()->lastFrame()),
|
frames.insert(std::clamp(tag->fromFrame(), 0, doc->sprite()->lastFrame()),
|
||||||
std::clamp(tag->toFrame(), 0, doc->sprite()->lastFrame()));
|
std::clamp(tag->toFrame(), 0, doc->sprite()->lastFrame()));
|
||||||
}
|
}
|
||||||
|
else if (isOneImageOnly())
|
||||||
|
frames.insert(0);
|
||||||
else {
|
else {
|
||||||
frames.insert(0, doc->sprite()->lastFrame());
|
frames.insert(0, doc->sprite()->lastFrame());
|
||||||
}
|
}
|
||||||
@ -137,7 +146,10 @@ doc::SelectedFrames DocExporter::Item::getSelectedFrames() const
|
|||||||
|
|
||||||
class DocExporter::Sample {
|
class DocExporter::Sample {
|
||||||
public:
|
public:
|
||||||
Sample(Doc* document, Sprite* sprite, SelectedLayers* selLayers,
|
Sample(Doc* document,
|
||||||
|
Sprite* sprite,
|
||||||
|
const ImageRef& image,
|
||||||
|
SelectedLayers* selLayers,
|
||||||
frame_t frame,
|
frame_t frame,
|
||||||
const Tag* tag,
|
const Tag* tag,
|
||||||
const std::string& filename,
|
const std::string& filename,
|
||||||
@ -145,6 +157,7 @@ public:
|
|||||||
const bool extrude) :
|
const bool extrude) :
|
||||||
m_document(document),
|
m_document(document),
|
||||||
m_sprite(sprite),
|
m_sprite(sprite),
|
||||||
|
m_image(image),
|
||||||
m_selLayers(selLayers),
|
m_selLayers(selLayers),
|
||||||
m_frame(frame),
|
m_frame(frame),
|
||||||
m_tag(tag),
|
m_tag(tag),
|
||||||
@ -153,9 +166,10 @@ public:
|
|||||||
m_extrude(extrude),
|
m_extrude(extrude),
|
||||||
m_isLinked(false),
|
m_isLinked(false),
|
||||||
m_isDuplicated(false),
|
m_isDuplicated(false),
|
||||||
m_originalSize(sprite->width(), sprite->height()),
|
m_originalSize(image ? image->width(): sprite->width(),
|
||||||
m_trimmedBounds(0, 0, sprite->width(), sprite->height()),
|
image ? image->height(): sprite->height()),
|
||||||
m_inTextureBounds(std::make_shared<gfx::Rect>(0, 0, sprite->width(), sprite->height())) {
|
m_trimmedBounds(m_originalSize),
|
||||||
|
m_inTextureBounds(std::make_shared<gfx::Rect>(m_trimmedBounds)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Doc* document() const { return m_document; }
|
Doc* document() const { return m_document; }
|
||||||
@ -221,6 +235,11 @@ public:
|
|||||||
ImageRef createRender(ImageBufferPtr& imageBuf) {
|
ImageRef createRender(ImageBufferPtr& imageBuf) {
|
||||||
ASSERT(m_sprite);
|
ASSERT(m_sprite);
|
||||||
|
|
||||||
|
// We use the m_image as it is, it doesn't require a special
|
||||||
|
// render.
|
||||||
|
if (m_image)
|
||||||
|
return m_image;
|
||||||
|
|
||||||
ImageRef render(
|
ImageRef render(
|
||||||
Image::create(m_sprite->pixelFormat(),
|
Image::create(m_sprite->pixelFormat(),
|
||||||
m_trimmedBounds.w,
|
m_trimmedBounds.w,
|
||||||
@ -266,19 +285,32 @@ public:
|
|||||||
for (int j=0; j<3; ++j) {
|
for (int j=0; j<3; ++j) {
|
||||||
for (int i=0; i<3; ++i) {
|
for (int i=0; i<3; ++i) {
|
||||||
gfx::Clip clip(x+dx[i], y+dy[j], gfx::RectT<int>(srcx[i], srcy[j], szx[i], szy[j]));
|
gfx::Clip clip(x+dx[i], y+dy[j], gfx::RectT<int>(srcx[i], srcy[j], szx[i], szy[j]));
|
||||||
render.renderSprite(dst, m_sprite, m_frame, clip);
|
if (m_image) {
|
||||||
|
dst->copy(m_image.get(), clip);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
render.renderSprite(dst, m_sprite, m_frame, clip);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
gfx::Clip clip(x, y, m_trimmedBounds);
|
gfx::Clip clip(x, y, m_trimmedBounds);
|
||||||
render.renderSprite(dst, m_sprite, m_frame, clip);
|
if (m_image) {
|
||||||
|
dst->copy(m_image.get(), clip);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
render.renderSprite(dst, m_sprite, m_frame, clip);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Doc* m_document;
|
Doc* m_document;
|
||||||
Sprite* m_sprite;
|
Sprite* m_sprite;
|
||||||
|
// In case that this Sample references just one image to export
|
||||||
|
// (e.g. like a Tileset tile image) this can be != nullptr.
|
||||||
|
ImageRef m_image;
|
||||||
SelectedLayers* m_selLayers;
|
SelectedLayers* m_selLayers;
|
||||||
frame_t m_frame;
|
frame_t m_frame;
|
||||||
const Tag* m_tag;
|
const Tag* m_tag;
|
||||||
@ -347,7 +379,7 @@ public:
|
|||||||
int shapePadding,
|
int shapePadding,
|
||||||
int& width, int& height,
|
int& width, int& height,
|
||||||
base::task_token& token) override {
|
base::task_token& token) override {
|
||||||
DX_TRACE("SimpleLayoutSamples type", (int)m_type, width, height);
|
DX_TRACE("DX: SimpleLayoutSamples type", (int)m_type, width, height);
|
||||||
|
|
||||||
const bool breakBands =
|
const bool breakBands =
|
||||||
(m_type == SpriteSheetType::Columns ||
|
(m_type == SpriteSheetType::Columns ||
|
||||||
@ -479,7 +511,7 @@ public:
|
|||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
DX_TRACE("-> SimpleLayoutSamples", width, height);
|
DX_TRACE("DX: -> SimpleLayoutSamples", width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -675,7 +707,7 @@ Doc* DocExporter::exportSheet(Context* ctx, base::task_token& token)
|
|||||||
|
|
||||||
// Save the image files.
|
// Save the image files.
|
||||||
if (!m_textureFilename.empty()) {
|
if (!m_textureFilename.empty()) {
|
||||||
DX_TRACE("DocExporter::exportSheet", m_textureFilename);
|
DX_TRACE("DX: exportSheet", m_textureFilename);
|
||||||
textureDocument->setFilename(m_textureFilename.c_str());
|
textureDocument->setFilename(m_textureFilename.c_str());
|
||||||
int ret = save_document(ctx, textureDocument.get());
|
int ret = save_document(ctx, textureDocument.get());
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
@ -702,11 +734,18 @@ void DocExporter::addDocument(
|
|||||||
const doc::SelectedLayers* selLayers,
|
const doc::SelectedLayers* selLayers,
|
||||||
const doc::SelectedFrames* selFrames)
|
const doc::SelectedFrames* selFrames)
|
||||||
{
|
{
|
||||||
DX_TRACE("DocExporter::addDocument doc=", doc, "tag=", tag);
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DocExporter::addImage(
|
||||||
|
Doc* doc,
|
||||||
|
const doc::ImageRef& image)
|
||||||
|
{
|
||||||
|
DX_TRACE("DX: addImage doc=", doc, "image=", image.get());
|
||||||
|
m_documents.push_back(Item(doc, image));
|
||||||
|
}
|
||||||
|
|
||||||
int DocExporter::addDocumentSamples(
|
int DocExporter::addDocumentSamples(
|
||||||
Doc* doc,
|
Doc* doc,
|
||||||
const doc::Tag* thisTag,
|
const doc::Tag* thisTag,
|
||||||
@ -715,7 +754,7 @@ int DocExporter::addDocumentSamples(
|
|||||||
const doc::SelectedLayers* selLayers,
|
const doc::SelectedLayers* selLayers,
|
||||||
const doc::SelectedFrames* selFrames)
|
const doc::SelectedFrames* selFrames)
|
||||||
{
|
{
|
||||||
DX_TRACE("DocExporter::addDocumentSamples");
|
DX_TRACE("DX: addDocumentSamples");
|
||||||
|
|
||||||
std::vector<const Tag*> tags;
|
std::vector<const Tag*> tags;
|
||||||
|
|
||||||
@ -804,6 +843,36 @@ int DocExporter::addDocumentSamples(
|
|||||||
return std::max(1, items);
|
return std::max(1, items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int DocExporter::addTilesetsSamples(
|
||||||
|
Doc* doc,
|
||||||
|
const doc::SelectedLayers* selLayers)
|
||||||
|
{
|
||||||
|
LayerList layers;
|
||||||
|
if (selLayers)
|
||||||
|
layers = selLayers->toAllLayersList();
|
||||||
|
else
|
||||||
|
layers = doc->sprite()->allVisibleLayers();
|
||||||
|
|
||||||
|
std::set<doc::ObjectId> alreadyExported;
|
||||||
|
int items = 0;
|
||||||
|
for (auto& layer : layers) {
|
||||||
|
if (layer->isTilemap()) {
|
||||||
|
Tileset* ts = dynamic_cast<LayerTilemap*>(layer)->tileset();
|
||||||
|
|
||||||
|
if (alreadyExported.find(ts->id()) == alreadyExported.end()) {
|
||||||
|
for (const ImageRef& image : *ts) {
|
||||||
|
addImage(doc, image);
|
||||||
|
++items;
|
||||||
|
}
|
||||||
|
alreadyExported.insert(ts->id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DX_TRACE("DX: addTilesetsSamples items=", items);
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
void DocExporter::captureSamples(Samples& samples,
|
void DocExporter::captureSamples(Samples& samples,
|
||||||
base::task_token& token)
|
base::task_token& token)
|
||||||
{
|
{
|
||||||
@ -834,24 +903,34 @@ void DocExporter::captureSamples(Samples& samples,
|
|||||||
(tag != nullptr)); // Has tag
|
(tag != nullptr)); // Has tag
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::Rect spriteBounds = sprite->bounds();
|
gfx::Rect spriteBounds;
|
||||||
if (m_trimSprite) {
|
|
||||||
if (m_cache.spriteId == sprite->id() &&
|
|
||||||
m_cache.spriteVer == sprite->version() &&
|
|
||||||
m_cache.trimmedByGrid == m_trimByGrid) {
|
|
||||||
spriteBounds = m_cache.trimmedBounds;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
spriteBounds = get_trimmed_bounds(sprite, m_trimByGrid);
|
|
||||||
if (spriteBounds.isEmpty())
|
|
||||||
spriteBounds = gfx::Rect(0, 0, 1, 1);
|
|
||||||
|
|
||||||
// Cache trimmed bounds so we don't have to recalculate them
|
// This item is only one image (e.g. a tileset tile)
|
||||||
// in the next iteration/preview.
|
if (item.isOneImageOnly()) {
|
||||||
m_cache.spriteId = sprite->id();
|
ASSERT(item.image);
|
||||||
m_cache.spriteVer = sprite->version();
|
spriteBounds = item.image->bounds();
|
||||||
m_cache.trimmedByGrid = m_trimByGrid;
|
}
|
||||||
m_cache.trimmedBounds = spriteBounds;
|
// This item comes from the sprite canvas
|
||||||
|
else {
|
||||||
|
spriteBounds = sprite->bounds();
|
||||||
|
if (m_trimSprite) {
|
||||||
|
if (m_cache.spriteId == sprite->id() &&
|
||||||
|
m_cache.spriteVer == sprite->version() &&
|
||||||
|
m_cache.trimmedByGrid == m_trimByGrid) {
|
||||||
|
spriteBounds = m_cache.trimmedBounds;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
spriteBounds = get_trimmed_bounds(sprite, m_trimByGrid);
|
||||||
|
if (spriteBounds.isEmpty())
|
||||||
|
spriteBounds = gfx::Rect(0, 0, 1, 1);
|
||||||
|
|
||||||
|
// Cache trimmed bounds so we don't have to recalculate them
|
||||||
|
// in the next iteration/preview.
|
||||||
|
m_cache.spriteId = sprite->id();
|
||||||
|
m_cache.spriteVer = sprite->version();
|
||||||
|
m_cache.trimmedByGrid = m_trimByGrid;
|
||||||
|
m_cache.trimmedBounds = spriteBounds;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -878,8 +957,9 @@ void DocExporter::captureSamples(Samples& samples,
|
|||||||
std::string filename = filename_formatter(format, fnInfo);
|
std::string filename = filename_formatter(format, fnInfo);
|
||||||
|
|
||||||
Sample sample(
|
Sample sample(
|
||||||
doc, sprite, item.selLayers.get(), frame, innerTag,
|
doc, sprite, item.image, item.selLayers.get(),
|
||||||
filename, m_innerPadding, m_extrude);
|
frame, innerTag, filename,
|
||||||
|
m_innerPadding, m_extrude);
|
||||||
Cel* cel = nullptr;
|
Cel* cel = nullptr;
|
||||||
Cel* link = nullptr;
|
Cel* link = nullptr;
|
||||||
bool done = false;
|
bool done = false;
|
||||||
@ -892,7 +972,8 @@ void DocExporter::captureSamples(Samples& samples,
|
|||||||
|
|
||||||
// Re-use linked samples
|
// Re-use linked samples
|
||||||
bool alreadyTrimmed = false;
|
bool alreadyTrimmed = false;
|
||||||
if (link && m_mergeDuplicates) {
|
if (link && m_mergeDuplicates &&
|
||||||
|
!item.isOneImageOnly()) {
|
||||||
for (const Sample& other : samples) {
|
for (const Sample& other : samples) {
|
||||||
if (token.canceled())
|
if (token.canceled())
|
||||||
return;
|
return;
|
||||||
@ -915,7 +996,8 @@ void DocExporter::captureSamples(Samples& samples,
|
|||||||
ASSERT(done || (!done && tag));
|
ASSERT(done || (!done && tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!done && (m_ignoreEmptyCels || m_trimCels)) {
|
if (!done && (m_ignoreEmptyCels || m_trimCels) &&
|
||||||
|
!item.isOneImageOnly()) {
|
||||||
// Ignore empty cels
|
// Ignore empty cels
|
||||||
if (layer && layer->isImage() && !cel && m_ignoreEmptyCels)
|
if (layer && layer->isImage() && !cel && m_ignoreEmptyCels)
|
||||||
continue;
|
continue;
|
||||||
@ -1306,6 +1388,9 @@ void DocExporter::createDataFile(const Samples& samples,
|
|||||||
|
|
||||||
bool firstTag = true;
|
bool firstTag = true;
|
||||||
for (auto& item : m_documents) {
|
for (auto& item : m_documents) {
|
||||||
|
if (item.isOneImageOnly())
|
||||||
|
continue;
|
||||||
|
|
||||||
Doc* doc = item.doc;
|
Doc* doc = item.doc;
|
||||||
Sprite* sprite = doc->sprite();
|
Sprite* sprite = doc->sprite();
|
||||||
|
|
||||||
@ -1337,6 +1422,9 @@ void DocExporter::createDataFile(const Samples& samples,
|
|||||||
if (m_listLayers) {
|
if (m_listLayers) {
|
||||||
LayerList metaLayers;
|
LayerList metaLayers;
|
||||||
for (auto& item : m_documents) {
|
for (auto& item : m_documents) {
|
||||||
|
if (item.isOneImageOnly())
|
||||||
|
continue;
|
||||||
|
|
||||||
Doc* doc = item.doc;
|
Doc* doc = item.doc;
|
||||||
Sprite* sprite = doc->sprite();
|
Sprite* sprite = doc->sprite();
|
||||||
Layer* root = sprite->root();
|
Layer* root = sprite->root();
|
||||||
@ -1432,6 +1520,9 @@ void DocExporter::createDataFile(const Samples& samples,
|
|||||||
|
|
||||||
bool firstSlice = true;
|
bool firstSlice = true;
|
||||||
for (auto& item : m_documents) {
|
for (auto& item : m_documents) {
|
||||||
|
if (item.isOneImageOnly())
|
||||||
|
continue;
|
||||||
|
|
||||||
Doc* doc = item.doc;
|
Doc* doc = item.doc;
|
||||||
Sprite* sprite = doc->sprite();
|
Sprite* sprite = doc->sprite();
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "base/disable_copying.h"
|
#include "base/disable_copying.h"
|
||||||
#include "base/task.h"
|
#include "base/task.h"
|
||||||
#include "doc/frame.h"
|
#include "doc/frame.h"
|
||||||
|
#include "doc/image_ref.h"
|
||||||
#include "doc/image_buffer.h"
|
#include "doc/image_buffer.h"
|
||||||
#include "doc/object_id.h"
|
#include "doc/object_id.h"
|
||||||
#include "doc/object_version.h"
|
#include "doc/object_version.h"
|
||||||
@ -82,6 +83,10 @@ namespace app {
|
|||||||
const doc::SelectedLayers* selLayers,
|
const doc::SelectedLayers* selLayers,
|
||||||
const doc::SelectedFrames* selFrames);
|
const doc::SelectedFrames* selFrames);
|
||||||
|
|
||||||
|
void addImage(
|
||||||
|
Doc* doc,
|
||||||
|
const doc::ImageRef& image);
|
||||||
|
|
||||||
int addDocumentSamples(
|
int addDocumentSamples(
|
||||||
Doc* doc,
|
Doc* doc,
|
||||||
const doc::Tag* tag,
|
const doc::Tag* tag,
|
||||||
@ -90,6 +95,10 @@ namespace app {
|
|||||||
const doc::SelectedLayers* selLayers,
|
const doc::SelectedLayers* selLayers,
|
||||||
const doc::SelectedFrames* selFrames);
|
const doc::SelectedFrames* selFrames);
|
||||||
|
|
||||||
|
int addTilesetsSamples(
|
||||||
|
Doc* doc,
|
||||||
|
const doc::SelectedLayers* selLayers);
|
||||||
|
|
||||||
Doc* exportSheet(Context* ctx, base::task_token& token);
|
Doc* exportSheet(Context* ctx, base::task_token& token);
|
||||||
gfx::Size calculateSheetSize();
|
gfx::Size calculateSheetSize();
|
||||||
|
|
||||||
@ -121,11 +130,14 @@ namespace app {
|
|||||||
const doc::Tag* tag = nullptr;
|
const doc::Tag* tag = nullptr;
|
||||||
std::unique_ptr<doc::SelectedLayers> selLayers;
|
std::unique_ptr<doc::SelectedLayers> selLayers;
|
||||||
std::unique_ptr<doc::SelectedFrames> selFrames;
|
std::unique_ptr<doc::SelectedFrames> selFrames;
|
||||||
|
doc::ImageRef image;
|
||||||
|
|
||||||
Item(Doc* doc,
|
Item(Doc* doc,
|
||||||
const doc::Tag* tag,
|
const doc::Tag* tag,
|
||||||
const doc::SelectedLayers* selLayers,
|
const doc::SelectedLayers* selLayers,
|
||||||
const doc::SelectedFrames* selFrames);
|
const doc::SelectedFrames* selFrames);
|
||||||
|
Item(Doc* doc,
|
||||||
|
const doc::ImageRef& image);
|
||||||
Item(Item&& other);
|
Item(Item&& other);
|
||||||
~Item();
|
~Item();
|
||||||
|
|
||||||
@ -135,6 +147,8 @@ namespace app {
|
|||||||
|
|
||||||
int frames() const;
|
int frames() const;
|
||||||
doc::SelectedFrames getSelectedFrames() const;
|
doc::SelectedFrames getSelectedFrames() const;
|
||||||
|
|
||||||
|
bool isOneImageOnly() const { return image != nullptr; }
|
||||||
};
|
};
|
||||||
typedef std::vector<Item> Items;
|
typedef std::vector<Item> Items;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user