mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-06 03:39:51 +00:00
Add 'Extrude' option to 'Export Sprite Sheet' command (fix #1890)
Merged #1978 (squashed). The only solved conflict was that now ExportSpriteSheet use params, so we've added the "extrude" param to ExportSpriteSheetParams.
This commit is contained in:
parent
3dc76d08c4
commit
cf1711c2af
@ -425,6 +425,7 @@
|
||||
<option id="shape_padding" type="int" default="0" />
|
||||
<option id="inner_padding" type="int" default="0" />
|
||||
<option id="trim" type="bool" default="false" />
|
||||
<option id="extrude" type="bool" default="false" />
|
||||
<option id="open_generated" type="bool" default="false" />
|
||||
<option id="layer" type="std::string" />
|
||||
<option id="frame_tag" type="std::string" />
|
||||
|
@ -521,6 +521,7 @@ border = Border:
|
||||
shape = Shape:
|
||||
inner = Inner:
|
||||
trim = Trim
|
||||
extrude = Extrude
|
||||
width = Width:
|
||||
height = Height:
|
||||
best_fit = Best fit for texture
|
||||
|
@ -18,6 +18,7 @@
|
||||
<vbox>
|
||||
<check id="padding_enabled" text="@.padding" />
|
||||
<check id="trim_enabled" text="@.trim" />
|
||||
<check id="extrude_enabled" text="@.extrude" />
|
||||
</vbox>
|
||||
<grid columns="2" id="padding_container" cell_hspan="2">
|
||||
<label text="@.border" />
|
||||
|
@ -179,6 +179,7 @@ struct ExportSpriteSheetParams : public NewParams {
|
||||
Param<int> shapePadding { this, 0, "shapePadding" };
|
||||
Param<int> innerPadding { this, 0, "innerPadding" };
|
||||
Param<bool> trim { this, false, "trim" };
|
||||
Param<bool> extrude { this, false, "extrude" };
|
||||
Param<bool> openGenerated { this, false, "openGenerated" };
|
||||
Param<std::string> layer { this, std::string(), "layer" };
|
||||
Param<std::string> tag { this, std::string(), "tag" };
|
||||
@ -218,6 +219,7 @@ public:
|
||||
|
||||
openGenerated()->setSelected(params.openGenerated());
|
||||
trimEnabled()->setSelected(params.trim());
|
||||
extrudeEnabled()->setSelected(params.extrude());
|
||||
|
||||
borderPadding()->setTextf("%d", params.borderPadding());
|
||||
shapePadding()->setTextf("%d", params.shapePadding());
|
||||
@ -392,6 +394,10 @@ public:
|
||||
return trimEnabled()->isSelected();
|
||||
}
|
||||
|
||||
bool extrudeValue() const {
|
||||
return extrudeEnabled()->isSelected();
|
||||
}
|
||||
|
||||
bool openGeneratedValue() const {
|
||||
return openGenerated()->isSelected();
|
||||
}
|
||||
@ -680,6 +686,7 @@ void ExportSpriteSheetCommand::onExecute(Context* context)
|
||||
docPref.spriteSheet.shapePadding (params.shapePadding (window.shapePaddingValue()));
|
||||
docPref.spriteSheet.innerPadding (params.innerPadding (window.innerPaddingValue()));
|
||||
docPref.spriteSheet.trim (params.trim (window.trimValue()));
|
||||
docPref.spriteSheet.extrude (params.extrude (window.extrudeValue()));
|
||||
docPref.spriteSheet.openGenerated (params.openGenerated (window.openGeneratedValue()));
|
||||
docPref.spriteSheet.layer (params.layer (window.layerValue()));
|
||||
docPref.spriteSheet.frameTag (params.tag (window.frameTagValue()));
|
||||
@ -716,6 +723,7 @@ void ExportSpriteSheetCommand::onExecute(Context* context)
|
||||
const int shapePadding = base::clamp(params.shapePadding(), 0, 100);
|
||||
const int innerPadding = base::clamp(params.innerPadding(), 0, 100);
|
||||
const bool trimCels = params.trim();
|
||||
const bool extrude = params.extrude();
|
||||
const bool listLayers = params.listLayers();
|
||||
const bool listTags = params.listTags();
|
||||
const bool listSlices = params.listSlices();
|
||||
@ -799,6 +807,7 @@ void ExportSpriteSheetCommand::onExecute(Context* context)
|
||||
exporter.setShapePadding(shapePadding);
|
||||
exporter.setInnerPadding(innerPadding);
|
||||
exporter.setTrimCels(trimCels);
|
||||
exporter.setExtrude(extrude);
|
||||
if (listLayers) exporter.setListLayers(true);
|
||||
if (listTags) exporter.setListFrameTags(true);
|
||||
if (listSlices) exporter.setListSlices(true);
|
||||
|
@ -169,13 +169,14 @@ doc::SelectedFrames DocExporter::Item::getSelectedFrames() const
|
||||
class DocExporter::Sample {
|
||||
public:
|
||||
Sample(Doc* document, Sprite* sprite, SelectedLayers* selLayers,
|
||||
frame_t frame, const std::string& filename, int innerPadding) :
|
||||
frame_t frame, const std::string& filename, int innerPadding, bool extrude) :
|
||||
m_document(document),
|
||||
m_sprite(sprite),
|
||||
m_selLayers(selLayers),
|
||||
m_frame(frame),
|
||||
m_filename(filename),
|
||||
m_innerPadding(innerPadding),
|
||||
m_extrude(extrude),
|
||||
m_bounds(new SampleBounds(sprite)),
|
||||
m_isDuplicated(false) {
|
||||
}
|
||||
@ -194,9 +195,12 @@ public:
|
||||
const gfx::Rect& inTextureBounds() const { return m_bounds->inTextureBounds(); }
|
||||
|
||||
gfx::Size requiredSize() const {
|
||||
// if extrude option is enabled, an extra pixel is needed for each side
|
||||
// left+right borders and top+bottom borders
|
||||
int extraExtrudePixels = m_extrude ? 2 : 0;
|
||||
gfx::Size size = m_bounds->trimmedBounds().size();
|
||||
size.w += 2*m_innerPadding;
|
||||
size.h += 2*m_innerPadding;
|
||||
size.w += 2*m_innerPadding + extraExtrudePixels;
|
||||
size.h += 2*m_innerPadding + extraExtrudePixels;
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -223,6 +227,7 @@ private:
|
||||
frame_t m_frame;
|
||||
std::string m_filename;
|
||||
int m_innerPadding;
|
||||
bool m_extrude;
|
||||
SampleBoundsPtr m_bounds;
|
||||
bool m_isDuplicated;
|
||||
};
|
||||
@ -391,6 +396,7 @@ DocExporter::DocExporter()
|
||||
, m_shapePadding(0)
|
||||
, m_innerPadding(0)
|
||||
, m_trimCels(false)
|
||||
, m_extrude(false)
|
||||
, m_listFrameTags(false)
|
||||
, m_listLayers(false)
|
||||
, m_listSlices(false)
|
||||
@ -510,7 +516,7 @@ void DocExporter::captureSamples(Samples& samples)
|
||||
|
||||
std::string filename = filename_formatter(format, fnInfo);
|
||||
|
||||
Sample sample(doc, sprite, item.selLayers, frame, filename, m_innerPadding);
|
||||
Sample sample(doc, sprite, item.selLayers, frame, filename, m_innerPadding, m_extrude);
|
||||
Cel* cel = nullptr;
|
||||
Cel* link = nullptr;
|
||||
bool done = false;
|
||||
@ -552,7 +558,7 @@ void DocExporter::captureSamples(Samples& samples)
|
||||
|
||||
sampleRender->setMaskColor(sprite->transparentColor());
|
||||
clear_image(sampleRender.get(), sprite->transparentColor());
|
||||
renderSample(sample, sampleRender.get(), 0, 0);
|
||||
renderSample(sample, sampleRender.get(), 0, 0, false);
|
||||
|
||||
gfx::Rect frameBounds;
|
||||
doc::color_t refColor = 0;
|
||||
@ -730,7 +736,8 @@ void DocExporter::renderTexture(Context* ctx, const Samples& samples, Image* tex
|
||||
|
||||
renderSample(sample, textureImage,
|
||||
sample.inTextureBounds().x+m_innerPadding,
|
||||
sample.inTextureBounds().y+m_innerPadding);
|
||||
sample.inTextureBounds().y+m_innerPadding,
|
||||
m_extrude);
|
||||
}
|
||||
}
|
||||
|
||||
@ -740,6 +747,16 @@ void DocExporter::createDataFile(const Samples& samples, std::ostream& os, Image
|
||||
std::string frames_end;
|
||||
bool filename_as_key = false;
|
||||
bool filename_as_attr = false;
|
||||
int nonExtrudedPosition = 0;
|
||||
int nonExtrudedSize = 0;
|
||||
|
||||
// if the the image was extruded then the exported meta-information (JSON)
|
||||
// should inform where start the real image (+1 displaced) and its
|
||||
// size (-2 pixels: one per each dimension compared the extruded image)
|
||||
if (m_extrude) {
|
||||
nonExtrudedPosition += 1;
|
||||
nonExtrudedSize -= 2;
|
||||
}
|
||||
|
||||
// TODO we should use some string templates system here
|
||||
switch (m_dataFormat) {
|
||||
@ -773,10 +790,10 @@ void DocExporter::createDataFile(const Samples& samples, std::ostream& os, Image
|
||||
<< " \"filename\": \"" << escape_for_json(sample.filename()) << "\",\n";
|
||||
|
||||
os << " \"frame\": { "
|
||||
<< "\"x\": " << frameBounds.x << ", "
|
||||
<< "\"y\": " << frameBounds.y << ", "
|
||||
<< "\"w\": " << frameBounds.w << ", "
|
||||
<< "\"h\": " << frameBounds.h << " },\n"
|
||||
<< "\"x\": " << frameBounds.x + nonExtrudedPosition << ", "
|
||||
<< "\"y\": " << frameBounds.y + nonExtrudedPosition << ", "
|
||||
<< "\"w\": " << frameBounds.w + nonExtrudedSize << ", "
|
||||
<< "\"h\": " << frameBounds.h + nonExtrudedSize << " },\n"
|
||||
<< " \"rotated\": false,\n"
|
||||
<< " \"trimmed\": " << (sample.trimmed() ? "true": "false") << ",\n"
|
||||
<< " \"spriteSourceSize\": { "
|
||||
@ -977,17 +994,44 @@ void DocExporter::createDataFile(const Samples& samples, std::ostream& os, Image
|
||||
<< "}\n";
|
||||
}
|
||||
|
||||
void DocExporter::renderSample(const Sample& sample, doc::Image* dst, int x, int y) const
|
||||
void DocExporter::renderSample(const Sample& sample, doc::Image* dst, int x, int y, bool extrude) const
|
||||
{
|
||||
gfx::Clip clip(x, y, sample.trimmedBounds());
|
||||
|
||||
RestoreVisibleLayers layersVisibility;
|
||||
if (sample.selectedLayers())
|
||||
layersVisibility.showSelectedLayers(sample.sprite(),
|
||||
*sample.selectedLayers());
|
||||
|
||||
render::Render render;
|
||||
render.renderSprite(dst, sample.sprite(), sample.frame(), clip);
|
||||
if (extrude) {
|
||||
const gfx::Rect& trim = sample.trimmedBounds();
|
||||
|
||||
// Displaced position onto the destination texture
|
||||
int dx[] = {0, 1, trim.w+1};
|
||||
int dy[] = {0, 1, trim.h+1};
|
||||
|
||||
// Starting point of the area to be copied from the original image
|
||||
// taking into account the size of the trimmed sprite
|
||||
int srcx[] = {trim.x, trim.x, trim.x2()-1};
|
||||
int srcy[] = {trim.y, trim.y, trim.y2()-1};
|
||||
|
||||
// Size of the area to be copied from original image, starting at
|
||||
// the point (srcx[i], srxy[j])
|
||||
int szx[] = {1, trim.w, 1};
|
||||
int szy[] = {1, trim.h, 1};
|
||||
|
||||
// Render a 9-patch image extruding the sample one pixel on each
|
||||
// side.
|
||||
for(int j=0; j<3; ++j) {
|
||||
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]));
|
||||
render.renderSprite(dst, sample.sprite(), sample.frame(), clip);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
gfx::Clip clip(x, y, sample.trimmedBounds());
|
||||
render.renderSprite(dst, sample.sprite(), sample.frame(), clip);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -54,6 +54,7 @@ namespace app {
|
||||
int shapePadding() const { return m_shapePadding; }
|
||||
int innerPadding() const { return m_innerPadding; }
|
||||
bool trimCels() const { return m_trimCels; }
|
||||
bool extrude() const { return m_extrude; }
|
||||
const std::string& filenameFormat() const { return m_filenameFormat; }
|
||||
bool listFrameTags() const { return m_listFrameTags; }
|
||||
bool listLayers() const { return m_listLayers; }
|
||||
@ -69,6 +70,7 @@ namespace app {
|
||||
void setShapePadding(int padding) { m_shapePadding = padding; }
|
||||
void setInnerPadding(int padding) { m_innerPadding = padding; }
|
||||
void setTrimCels(bool trim) { m_trimCels = trim; }
|
||||
void setExtrude(bool extrude) { m_extrude = extrude; }
|
||||
void setFilenameFormat(const std::string& format) { m_filenameFormat = format; }
|
||||
void setListFrameTags(bool value) { m_listFrameTags = value; }
|
||||
void setListLayers(bool value) { m_listLayers = value; }
|
||||
@ -97,7 +99,7 @@ namespace app {
|
||||
Doc* createEmptyTexture(const Samples& samples) const;
|
||||
void renderTexture(Context* ctx, const Samples& samples, doc::Image* textureImage) const;
|
||||
void createDataFile(const Samples& samples, std::ostream& os, doc::Image* textureImage);
|
||||
void renderSample(const Sample& sample, doc::Image* dst, int x, int y) const;
|
||||
void renderSample(const Sample& sample, doc::Image* dst, int x, int y, bool extrude) const;
|
||||
|
||||
class Item {
|
||||
public:
|
||||
@ -133,6 +135,7 @@ namespace app {
|
||||
int m_shapePadding;
|
||||
int m_innerPadding;
|
||||
bool m_trimCels;
|
||||
bool m_extrude;
|
||||
Items m_documents;
|
||||
std::string m_filenameFormat;
|
||||
doc::ImageBufferPtr m_sampleRenderBuf;
|
||||
|
Loading…
x
Reference in New Issue
Block a user