From 7ea2b697ef588413d9f14b7a2b6131e1347bf203 Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Fri, 14 Jul 2023 10:27:38 +0900 Subject: [PATCH] pcx2clx: Add an option to crop sprite widths Refs https://github.com/diasurgical/devilutionX/issues/6361 --- src/internal/pcx2clx.cpp | 15 +++++++++++---- src/internal/pcx2clx_main.cpp | 21 ++++++++++++++------- src/public/include/pcx2clx.hpp | 3 +++ 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/internal/pcx2clx.cpp b/src/internal/pcx2clx.cpp index 215083e..19a3380 100644 --- a/src/internal/pcx2clx.cpp +++ b/src/internal/pcx2clx.cpp @@ -19,6 +19,7 @@ namespace dvl_gfx { std::optional PcxToClx(const uint8_t *data, size_t size, int numFramesOrFrameHeight, std::optional transparentColor, + const std::vector &cropWidths, std::vector &clxData, uint8_t *paletteData) { @@ -68,8 +69,12 @@ std::optional PcxToClx(const uint8_t *data, size_t size, clxData.resize(clxData.size() + FrameHeaderSize); // Frame header: + const uint16_t frameWidth = cropWidths.empty() + ? width + : cropWidths[std::min(cropWidths.size(), frame) - 1]; + WriteLE16(&clxData[frameHeaderPos], FrameHeaderSize); - WriteLE16(&clxData[frameHeaderPos + 2], static_cast(width)); + WriteLE16(&clxData[frameHeaderPos + 2], static_cast(frameWidth)); WriteLE16(&clxData[frameHeaderPos + 4], static_cast(frameHeight)); memset(&clxData[frameHeaderPos + 6], 0, 4); @@ -99,7 +104,7 @@ std::optional PcxToClx(const uint8_t *data, size_t size, const uint8_t *src = &frameBuffer[(frameHeight - (line + 1)) * width]; if (transparentColor) { unsigned solidRunWidth = 0; - for (const uint8_t *srcEnd = src + width; src != srcEnd; ++src) { + for (const uint8_t *srcEnd = src + frameWidth; src != srcEnd; ++src) { if (*src == *transparentColor) { if (solidRunWidth != 0) { AppendClxPixelsOrFillRun( @@ -145,6 +150,7 @@ std::optional PcxToClx(const uint8_t *data, size_t size, std::optional PcxToClx(const char *inputPath, const char *outputPath, int numFramesOrFrameHeight, std::optional transparentColor, + const std::vector &cropWidths, bool exportPalette, uintmax_t *inputFileSize, uintmax_t *outputFileSize) @@ -173,8 +179,9 @@ std::optional PcxToClx(const char *inputPath, const char *outputPath, std::vector clxData; std::array paletteData; - if (const std::optional error = PcxToClx(fileBuffer.get(), pixelDataSize, numFramesOrFrameHeight, transparentColor, - clxData, exportPalette ? paletteData.data() : nullptr); + if (const std::optional error = PcxToClx( + fileBuffer.get(), pixelDataSize, numFramesOrFrameHeight, transparentColor, + cropWidths, clxData, exportPalette ? paletteData.data() : nullptr); error.has_value()) { return error; } diff --git a/src/internal/pcx2clx_main.cpp b/src/internal/pcx2clx_main.cpp index 9cd39e8..cc4091a 100644 --- a/src/internal/pcx2clx_main.cpp +++ b/src/internal/pcx2clx_main.cpp @@ -20,12 +20,13 @@ constexpr char KHelp[] = R"(Usage: pcx2clx [options] files... Converts PCX sprite(s) to a CLX file. Options: - --output-dir Output directory. Default: input file directory. - --transparent-color Transparent color index. Default: none. - --num-sprites The number of vertically-stacked sprites. Default: 1. - --export-palette Export the palette as a .pal file. - --remove Remove the input files. - -q, --quiet Do not log anything. + --output-dir Output directory. Default: input file directory. + --transparent-color Transparent color index. Default: none. + --num-sprites The number of vertically-stacked sprites. Default: 1. + --crop-widths [,...] Crop sprites to the given width(s) by removing the right side of the sprite. Default: none. + --export-palette Export the palette as a .pal file. + --remove Remove the input files. + -q, --quiet Do not log anything. )"; struct Options { @@ -33,6 +34,7 @@ struct Options { std::optional outputDir; uint16_t numSprites = 1; std::optional transparentColor; + std::vector cropWidths; bool exportPalette = false; bool remove = false; bool quiet = false; @@ -72,6 +74,11 @@ tl::expected ParseArguments(int argc, char *argv[]) if (!value.has_value()) return tl::unexpected { std::move(value).error() }; options.transparentColor = *value; + } else if (arg == "--crop-widths") { + tl::expected, ArgumentError> value = ParseIntListArgument(state); + if (!value.has_value()) + return tl::unexpected { std::move(value).error() }; + options.cropWidths = *std::move(value); } else if (arg == "--export-palette") { options.exportPalette = true; } else if (arg == "--remove") { @@ -111,7 +118,7 @@ std::optional Run(const Options &options) uintmax_t inputFileSize; uintmax_t outputFileSize; if (std::optional error = PcxToClx(inputPath, outputPath.string().c_str(), options.numSprites, - options.transparentColor, options.exportPalette, &inputFileSize, &outputFileSize); + options.transparentColor, options.cropWidths, options.exportPalette, &inputFileSize, &outputFileSize); error.has_value()) { error->message.append(": ").append(inputPath); return error; diff --git a/src/public/include/pcx2clx.hpp b/src/public/include/pcx2clx.hpp index 4fea961..b21d1e6 100644 --- a/src/public/include/pcx2clx.hpp +++ b/src/public/include/pcx2clx.hpp @@ -17,18 +17,21 @@ namespace dvl_gfx { * @param size PCX buffer size. * @param numFramesOrFrameHeight Number of vertically-stacked frames if positive, frame height if negative. * @param transparentColor Palette index of the transparent color. + * @param cropWidths If non-empty, the sprites are cropped to the given width(s) by removing the right side of the sprite. * @param paletteData If non-null, PCX palette data (256 * 3 bytes). * @return std::optional */ std::optional PcxToClx(const uint8_t *data, size_t size, int numFramesOrFrameHeight, std::optional transparentColor, + const std::vector &cropWidths, std::vector &clxData, uint8_t *paletteData = nullptr); std::optional PcxToClx(const char *inputPath, const char *outputPath, int numFramesOrFrameHeight = 1, std::optional transparentColor = std::nullopt, + const std::vector &cropWidths = {}, bool exportPalette = false, uintmax_t *inputFileSize = nullptr, uintmax_t *outputFileSize = nullptr);