Skip to content
Permalink
Browse files

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.
  • Loading branch information...
dncampo authored and dacap committed Jan 10, 2019
1 parent 3dc76d0 commit cf1711c2affa6733bb0bd807936579fc1331ee74
@@ -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 @@ class ExportSpriteSheetWindow : public app::gen::ExportSpriteSheet {

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 @@ class ExportSpriteSheetWindow : public app::gen::ExportSpriteSheet {
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 @@ class DocExporter::Sample {
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 @@ class DocExporter::Sample {
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;

0 comments on commit cf1711c

Please sign in to comment.
You can’t perform that action at this time.