diff --git a/src/app/app.cpp b/src/app/app.cpp index 5d447eee6..aacf33e94 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -210,6 +210,8 @@ void App::initialize(int argc, const char* argv[]) // Procress options PRINTF("Processing options...\n"); + bool ignoreEmpty = false; + // Open file specified in the command line if (!options.values().empty()) { Console console; @@ -258,6 +260,10 @@ void App::initialize(int argc, const char* argv[]) importLayer = value.value(); importLayerSaveAs = value.value(); } + // --ignore-empty + else if (opt == &options.ignoreEmpty()) { + ignoreEmpty = true; + } // --save-as else if (opt == &options.saveAs()) { Document* doc = NULL; @@ -380,6 +386,9 @@ void App::initialize(int argc, const char* argv[]) if (m_exporter != NULL) { PRINTF("Exporting sheet...\n"); + if (ignoreEmpty) + m_exporter->setIgnoreEmptyCels(true); + m_exporter->exportSheet(); m_exporter.reset(NULL); } diff --git a/src/app/app_options.cpp b/src/app/app_options.cpp index 8a5cbbffc..7f7877342 100644 --- a/src/app/app_options.cpp +++ b/src/app/app_options.cpp @@ -48,6 +48,7 @@ AppOptions::AppOptions(int argc, const char* argv[]) , m_sheetPack(m_po.add("sheet-pack").description("Use a packing algorithm to avoid waste of space\nin the texture")) , m_splitLayers(m_po.add("split-layers").description("Import each layer of the next given sprite as\na separated image in the sheet")) , m_importLayer(m_po.add("import-layer").requiresValue("").description("Import just one layer of the next given sprite")) + , m_ignoreEmpty(m_po.add("ignore-empty").description("Do not export empty frames/cels")) , m_verbose(m_po.add("verbose").description("Explain what is being done")) , m_help(m_po.add("help").mnemonic('?').description("Display this help and exits")) , m_version(m_po.add("version").description("Output version information and exit")) diff --git a/src/app/app_options.h b/src/app/app_options.h index e1d56dcc9..19901d8a0 100644 --- a/src/app/app_options.h +++ b/src/app/app_options.h @@ -56,6 +56,7 @@ public: const Option& sheetPack() const { return m_sheetPack; } const Option& splitLayers() const { return m_splitLayers; } const Option& importLayer() const { return m_importLayer; } + const Option& ignoreEmpty() const { return m_ignoreEmpty; } bool hasExporterParams() const; @@ -82,6 +83,7 @@ private: Option& m_sheetPack; Option& m_splitLayers; Option& m_importLayer; + Option& m_ignoreEmpty; Option& m_verbose; Option& m_help; diff --git a/src/app/document_exporter.cpp b/src/app/document_exporter.cpp index 86c16d104..e15d792d6 100644 --- a/src/app/document_exporter.cpp +++ b/src/app/document_exporter.cpp @@ -32,6 +32,7 @@ #include "base/unique_ptr.h" #include "gfx/packing_rects.h" #include "gfx/size.h" +#include "raster/algorithm/shrink_bounds.h" #include "raster/cel.h" #include "raster/dithering_method.h" #include "raster/image.h" @@ -205,6 +206,7 @@ DocumentExporter::DocumentExporter() , m_texturePack(false) , m_scale(1.0) , m_scaleMode(DefaultScaleMode) + , m_ignoreEmptyCels(false) { } @@ -264,6 +266,7 @@ void DocumentExporter::exportSheet() void DocumentExporter::captureSamples(Samples& samples) { + ImageBufferPtr checkEmptyImageBuf; std::vector buf(32); for (auto& item : m_documents) { @@ -289,7 +292,35 @@ void DocumentExporter::captureSamples(Samples& samples) + "." + base::get_file_extension(filename)); } - samples.addSample(Sample(doc, sprite, layer, frame, filename)); + Sample sample(doc, sprite, layer, frame, filename); + + if (m_ignoreEmptyCels) { + if (layer && layer->isImage() && + !static_cast(layer)->getCel(frame)) { + // Empty cel this sample completely + continue; + } + + base::UniquePtr checkEmptyImage( + Image::create(sprite->pixelFormat(), + sprite->width(), + sprite->height(), + checkEmptyImageBuf)); + + checkEmptyImage->setMaskColor(sprite->transparentColor()); + clear_image(checkEmptyImage, sprite->transparentColor()); + renderSample(sample, checkEmptyImage, 0, 0); + + gfx::Rect frameBounds; + if (!algorithm::shrink_bounds(checkEmptyImage, frameBounds, + sprite->transparentColor())) { + // If shrink_bounds returns false, it's because the whole + // image is transparent (equal to the mask color). + continue; + } + } + + samples.addSample(sample); } } } @@ -355,12 +386,7 @@ void DocumentExporter::renderTexture(const Samples& samples, Image* textureImage int x = sample.inTextureBounds().x - sample.trimmedBounds().x; int y = sample.inTextureBounds().y - sample.trimmedBounds().y; - if (sample.layer()) { - layer_render(sample.layer(), textureImage, x, y, sample.frame()); - } - else { - sample.sprite()->render(textureImage, x, y, sample.frame()); - } + renderSample(sample, textureImage, x, y); } } @@ -415,4 +441,14 @@ void DocumentExporter::createDataFile(const Samples& samples, std::ostream& os, << "}\n"; } +void DocumentExporter::renderSample(const Sample& sample, raster::Image* dst, int x, int y) +{ + if (sample.layer()) { + layer_render(sample.layer(), dst, x, y, sample.frame()); + } + else { + sample.sprite()->render(dst, x, y, sample.frame()); + } +} + } // namespace app diff --git a/src/app/document_exporter.h b/src/app/document_exporter.h index a618e9bdd..122482172 100644 --- a/src/app/document_exporter.h +++ b/src/app/document_exporter.h @@ -89,6 +89,10 @@ namespace app { m_scaleMode = mode; } + void setIgnoreEmptyCels(bool ignore) { + m_ignoreEmptyCels = ignore; + } + void addDocument(Document* document, raster::Layer* layer = NULL) { m_documents.push_back(Item(document, layer)); } @@ -106,6 +110,7 @@ namespace app { Document* createEmptyTexture(const Samples& samples); void renderTexture(const Samples& samples, raster::Image* textureImage); void createDataFile(const Samples& samples, std::ostream& os, raster::Image* textureImage); + void renderSample(const Sample& sample, raster::Image* dst, int x, int y); class Item { public: @@ -126,6 +131,7 @@ namespace app { bool m_texturePack; double m_scale; ScaleMode m_scaleMode; + bool m_ignoreEmptyCels; Items m_documents; DISABLE_COPYING(DocumentExporter);