summaryrefslogtreecommitdiffhomepage
path: root/crop-tool
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2022-06-11 10:56:22 +0200
committerStanislaw Halik <sthalik@misaki.pl>2022-06-11 10:56:22 +0200
commit954c223d3276ae312274e9f0a3c47396b8cf9d60 (patch)
treed9b54e3f210bcc073e44a4809298a650a94fdb52 /crop-tool
parentb0925a6a5e16dce10cb9b5bd99b62f96b2953441 (diff)
.
Diffstat (limited to 'crop-tool')
-rw-r--r--crop-tool/CMakeLists.txt12
-rw-r--r--crop-tool/atlas.cpp61
-rw-r--r--crop-tool/atlas.hpp36
-rw-r--r--crop-tool/crop-tool.cpp58
-rw-r--r--crop-tool/serialize.cpp127
-rw-r--r--crop-tool/serialize.hpp41
6 files changed, 35 insertions, 300 deletions
diff --git a/crop-tool/CMakeLists.txt b/crop-tool/CMakeLists.txt
index cc38c51b..974a07e9 100644
--- a/crop-tool/CMakeLists.txt
+++ b/crop-tool/CMakeLists.txt
@@ -1,6 +1,8 @@
-find_package(OpenCV QUIET REQUIRED COMPONENTS core imgcodecs imgproc highgui)
+find_package(OpenCV QUIET REQUIRED COMPONENTS core imgcodecs imgproc)
+set(self "${PROJECT_NAME}-crop-tool")
file(GLOB sources "*.cpp" CONFIGURE_ARGS)
-add_executable(crop-tool ${sources})
-target_include_directories(crop-tool SYSTEM PRIVATE ${OpenCV_INCLUDE_DIRS})
-target_link_libraries(crop-tool opencv_highgui opencv_imgproc opencv_imgcodecs opencv_core)
-target_link_libraries(crop-tool Corrade::Utility Magnum::Trade)
+
+add_executable(${self} ${sources})
+target_include_directories(${self} SYSTEM PRIVATE ${OpenCV_INCLUDE_DIRS})
+target_link_libraries(${self} Corrade::Utility)
+target_link_libraries(${self} game-anim)
diff --git a/crop-tool/atlas.cpp b/crop-tool/atlas.cpp
deleted file mode 100644
index ca05cd15..00000000
--- a/crop-tool/atlas.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-#include "atlas.hpp"
-#include "serialize.hpp"
-#include "../defs.hpp"
-
-#include <filesystem>
-#include <opencv2/imgcodecs.hpp>
-
-void anim_atlas_row::add_entry(const anim_atlas_entry& x)
-{
- auto& frame = *x.frame;
- const auto& mat = x.mat;
- frame.offset = {xpos, ypos};
- frame.size = {mat.cols, mat.rows};
-
- ASSERT(mat.rows > 0 && mat.cols > 0);
- data.push_back(x);
- xpos += mat.cols;
- max_height = std::max(mat.rows, max_height);
-}
-
-void anim_atlas::advance_row()
-{
- auto& row = rows.back();
- if (row.data.empty())
- return;
- ASSERT(row.xpos); ASSERT(row.max_height);
- ypos += row.max_height;
- maxx = std::max(row.xpos, maxx);
- rows.push_back({{}, 0, 0, ypos});
-}
-
-Magnum::Vector2i anim_atlas::offset() const
-{
- const auto& row = rows.back();
- return {row.xpos, row.ypos};
-}
-
-Magnum::Vector2i anim_atlas::size() const
-{
- const anim_atlas_row& row = rows.back();
- // prevent accidentally writing out of bounds by forgetting to call
- // anim_atlas::advance_row() one last time prior to anim_atlas::size()
- return {std::max(maxx, row.xpos), ypos + row.max_height};
-}
-
-bool anim_atlas::dump(const std::filesystem::path& filename) const
-{
- auto sz = size();
- cv::Mat4b mat(sz[1], sz[0]);
- mat.setTo(0);
-
- for (const anim_atlas_row& row : rows)
- for (const anim_atlas_entry& x : row.data)
- {
- auto offset = x.frame->offset, size = x.frame->size;
- cv::Rect roi = {offset[0], offset[1], size[0], size[1]};
- x.mat.copyTo(mat(roi));
- }
-
- return cv::imwrite(filename.string(), mat);
-}
diff --git a/crop-tool/atlas.hpp b/crop-tool/atlas.hpp
deleted file mode 100644
index 675b6ff9..00000000
--- a/crop-tool/atlas.hpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#pragma once
-#include <vector>
-#include <Magnum/Magnum.h>
-#include <Magnum/Math/Vector2.h>
-#include <opencv2/core/mat.hpp>
-
-struct anim_frame;
-
-namespace std::filesystem { class path; }
-
-struct anim_atlas_entry
-{
- anim_frame* frame;
- const cv::Mat4b mat;
-};
-
-struct anim_atlas_row
-{
- std::vector<anim_atlas_entry> data;
- int max_height = 0, xpos = 0, ypos = 0;
-
- void add_entry(const anim_atlas_entry& x);
-};
-
-class anim_atlas
-{
- std::vector<anim_atlas_row> rows = {{}};
- int ypos = 0, maxx = 0;
-
-public:
- void add_entry(const anim_atlas_entry& x) { rows.back().add_entry(x); }
- void advance_row();
- Magnum::Vector2i offset() const;
- Magnum::Vector2i size() const;
- [[nodiscard]] bool dump(const std::filesystem::path& filename) const;
-};
diff --git a/crop-tool/crop-tool.cpp b/crop-tool/crop-tool.cpp
index 35089dd6..099ebfa1 100644
--- a/crop-tool/crop-tool.cpp
+++ b/crop-tool/crop-tool.cpp
@@ -1,13 +1,12 @@
#include "../defs.hpp"
-#include "atlas.hpp"
-#include "serialize.hpp"
+#include "anim/atlas.hpp"
+#include "anim/serialize.hpp"
#include <Corrade/Utility/Arguments.h>
#include <Corrade/Utility/Debug.h>
#include <Corrade/Utility/DebugStl.h>
#include <opencv2/core/mat.hpp>
#include <opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/imgproc/imgproc.hpp>
-#include <opencv2/highgui.hpp>
#include <optional>
#include <tuple>
#include <filesystem>
@@ -35,9 +34,10 @@ using Corrade::Utility::Debug;
using std::filesystem::path;
-struct options_ {
- std::optional<unsigned> width, height;
- std::optional<double> scale;
+struct options
+{
+ unsigned width = 0, height = 0;
+ double scale = 0;
path input_dir, output_dir;
};
@@ -71,7 +71,7 @@ static std::tuple<cv::Vec2i, cv::Vec2i, bool> find_image_bounds(const path& path
}
[[nodiscard]]
-static bool load_file(anim_group& group, options_& opts, anim_atlas& atlas, const path& filename)
+static bool load_file(anim_group& group, options& opts, anim_atlas& atlas, const path& filename)
{
auto mat = progn(
cv::Mat mat_ = cv::imread(filename.string(), cv::IMREAD_UNCHANGED);
@@ -93,18 +93,18 @@ static bool load_file(anim_group& group, options_& opts, anim_atlas& atlas, cons
cv::Size size{end - start}, dest_size;
- if (!opts.scale)
+ if (opts.scale == 0.0)
{
+ ASSERT(opts.width || opts.height);
if (opts.width)
- opts.scale = (double)*opts.width / size.width;
- else if (opts.height)
- opts.scale = (double)*opts.height / size.height;
+ opts.scale = (double)opts.width / size.width;
else
- std::abort();
+ opts.scale = (double)opts.height / size.height;
+ ASSERT(opts.scale > 1e-6);
}
- dest_size = {(int)std::round(*opts.scale * size.width),
- (int)std::round(*opts.scale * size.height)};
+ dest_size = {(int)std::round(opts.scale * size.width),
+ (int)std::round(opts.scale * size.height)};
if (size.width < dest_size.width || size.height < dest_size.height)
{
@@ -122,19 +122,17 @@ static bool load_file(anim_group& group, options_& opts, anim_atlas& atlas, cons
}
#endif
Magnum::Vector2i ground = {
- (int)std::round((group.ground[0] - start[0]) * *opts.scale),
- (int)std::round((group.ground[1] - start[1]) * *opts.scale),
+ (int)std::round((group.ground[0] - start[0]) * opts.scale),
+ (int)std::round((group.ground[1] - start[1]) * opts.scale),
};
- auto offset = atlas.offset();
-
- group.frames.push_back({ground, offset, {dest_size.width, dest_size.height}});
+ group.frames.push_back({ground, atlas.offset(), {dest_size.width, dest_size.height}});
atlas.add_entry({&group.frames.back(), std::move(mat)});
return true;
}
[[nodiscard]]
-static bool load_directory(anim_group& group, options_& opts, anim_atlas& atlas, const path& input_dir)
+static bool load_directory(anim_group& group, options& opts, anim_atlas& atlas, const path& input_dir)
{
if (std::error_code ec{}; !std::filesystem::exists(input_dir/".", ec))
{
@@ -184,7 +182,7 @@ static char* fix_argv0(char* argv0)
return argv0;
}
-static std::tuple<options_, int> parse_cmdline(int argc, const char* const* argv)
+static std::tuple<options, int> parse_cmdline(int argc, const char* const* argv)
{
Corrade::Utility::Arguments args{};
args.addOption('o', "output")
@@ -192,23 +190,23 @@ static std::tuple<options_, int> parse_cmdline(int argc, const char* const* argv
.addOption('W', "width", "")
.addOption('H', "height", "");
args.parse(argc, argv);
- options_ options;
+ options opts;
if (unsigned w = args.value<unsigned>("width"); w != 0)
- options.width = w;
+ opts.width = w;
if (unsigned h = args.value<unsigned>("height"); h != 0)
- options.height = h;
- if (!(!options.width ^ !options.height))
+ opts.height = h;
+ if (!(!opts.width ^ !opts.height))
{
Error{} << "exactly one of --width, --height must be given";
goto usage;
}
- options.output_dir = args.value<std::string>("output");
- options.input_dir = args.value<std::string>("directory");
+ opts.output_dir = args.value<std::string>("output");
+ opts.input_dir = args.value<std::string>("directory");
- if (options.output_dir.empty())
- options.output_dir = options.input_dir;
+ if (opts.output_dir.empty())
+ opts.output_dir = opts.input_dir;
- return {options, 0};
+ return { opts, 0};
usage:
Error{Error::Flag::NoNewlineAtTheEnd} << Corrade::Containers::StringView{args.usage()};
return {{}, EX_USAGE};
diff --git a/crop-tool/serialize.cpp b/crop-tool/serialize.cpp
deleted file mode 100644
index acefe436..00000000
--- a/crop-tool/serialize.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-#include "serialize.hpp"
-#include "../json.hpp"
-
-#include <algorithm>
-#include <utility>
-#include <fstream>
-#include <Corrade/Utility/Debug.h>
-#include <Corrade/Utility/DebugStl.h>
-
-using Corrade::Utility::Debug;
-using Corrade::Utility::Error;
-
-static constexpr
-std::pair<anim_direction, const char*> anim_direction_map[] = {
- { anim_direction::N, "n" },
- { anim_direction::NE, "ne" },
- { anim_direction::E, "e" },
- { anim_direction::SE, "se" },
- { anim_direction::S, "s" },
- { anim_direction::SW, "sw" },
- { anim_direction::W, "w" },
- { anim_direction::NW, "nw" },
-};
-
-const char* anim_group::direction_to_string(anim_direction group)
-{
- auto it = std::find_if(std::cbegin(anim_direction_map), std::cend(anim_direction_map),
- [=](const auto& pair) { return group == pair.first; });
- if (it != std::cend(anim_direction_map))
- return it->second;
- else
- return "(unknown)";
-}
-
-anim_direction anim_group::string_to_direction(const std::string& str)
-{
- auto it = std::find_if(std::cbegin(anim_direction_map), std::cend(anim_direction_map),
- [&](const auto& pair) { return str == pair.second; });
- if (it != std::cend(anim_direction_map))
- return it->first;
- else
- return (anim_direction)0;
-}
-
-namespace nlohmann {
-
-template<>
-struct adl_serializer<anim_direction> final {
- static void to_json(json& j, anim_direction x);
- static void from_json(const json& j, anim_direction& x);
-};
-
-template<>
-struct adl_serializer<Magnum::Vector2i> final {
- static void to_json(json& j, const Magnum::Vector2i& x);
- static void from_json(const json& j, Magnum::Vector2i& x);
-};
-
-void adl_serializer<Magnum::Vector2i>::to_json(json& j, const Magnum::Vector2i& x)
-{
- j["x"] = x[0];
- j["y"] = x[1];
-}
-
-void adl_serializer<Magnum::Vector2i>::from_json(const json& j, Magnum::Vector2i& x)
-{
- j.at("x").get_to(x[0]);
- j.at("y").get_to(x[1]);
-}
-
-void adl_serializer<anim_direction>::to_json(json& j, anim_direction x)
-{
- j = anim_group::direction_to_string(x);
-}
-
-void adl_serializer<anim_direction>::from_json(const json& j, anim_direction& x)
-{
- x = anim_group::string_to_direction(j);
-}
-
-} // namespace nlohmann
-
-NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(anim_frame, ground, offset, size);
-NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(anim_group, name, frames, ground);
-NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(anim, name, nframes, actionframe, fps, groups);
-
-std::optional<anim> anim::from_json(const std::filesystem::path& pathname)
-{
- using namespace nlohmann;
- std::ifstream s;
- s.exceptions(s.exceptions() | std::ios::failbit | std::ios::badbit);
- try {
- s.open(pathname, std::ios_base::in);
- } catch (const std::ios::failure& e) {
- Error{} << "failed to open" << pathname << ':' << e.what();
- return std::nullopt;
- }
- anim ret;
- try {
- json j;
- s >> j;
- using nlohmann::from_json;
- from_json(j, ret);
- } catch (const std::exception& e) {
- Error{} << "failed to parse" << pathname << ':' << e.what();
- return std::nullopt;
- }
- return std::make_optional(std::move(ret));
-}
-
-bool anim::to_json(const std::filesystem::path& pathname)
-{
- nlohmann::json j = *this;
-
- std::ofstream s;
- s.exceptions(s.exceptions() | std::ios::failbit | std::ios::badbit);
- try {
- s.open(pathname, std::ios_base::out | std::ios_base::trunc);
- } catch (const std::ios::failure& e) {
- Error{} << "failed to open" << pathname << "for writing:" << e.what();
- return false;
- }
- s << j.dump(4);
- s.flush();
-
- return true;
-}
diff --git a/crop-tool/serialize.hpp b/crop-tool/serialize.hpp
deleted file mode 100644
index 10fd9e18..00000000
--- a/crop-tool/serialize.hpp
+++ /dev/null
@@ -1,41 +0,0 @@
-#pragma once
-
-#include "../defs.hpp"
-#include <string>
-#include <array>
-#include <vector>
-#include <optional>
-#include <filesystem>
-#include <Magnum/Trade/ImageData.h>
-
-struct anim_frame final
-{
- Magnum::Vector2i ground, offset, size;
-};
-
-enum class anim_direction : unsigned char
-{
- N, NE, E, SE, S, SW, W, NW,
- COUNT = NW + 1,
-};
-
-struct anim_group final
-{
- std::string name;
- std::vector<anim_frame> frames;
- Magnum::Vector2i ground;
-
- static const char* direction_to_string(anim_direction group);
- static anim_direction string_to_direction(const std::string& str);
-};
-
-struct anim final
-{
- static std::optional<anim> from_json(const std::filesystem::path& pathname);
- bool to_json(const std::filesystem::path& pathname);
- static constexpr int default_fps = 24;
-
- std::string name;
- std::array<anim_group, (std::size_t)anim_direction::COUNT> groups;
- int nframes = 0, actionframe = -1, fps = default_fps;
-};