From d7d5cd4265aab0b939b57ea7237b56f2f5840642 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 11 Mar 2023 12:07:29 +0000 Subject: Initial version of texture packer Determines where a collection of smaller textures can be tiled into a single bigger image. Probably non-optimal. --- test/test-assetFactory.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'test/test-assetFactory.cpp') diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp index 204ffb3..ad62a93 100644 --- a/test/test-assetFactory.cpp +++ b/test/test-assetFactory.cpp @@ -7,6 +7,7 @@ #include "assetFactory/assetFactory.h" #include "assetFactory/object.h" +#include "assetFactory/texturePacker.h" #include "game/vehicles/railVehicle.h" #include "game/vehicles/railVehicleClass.h" #include "gfx/gl/sceneRenderer.h" @@ -125,3 +126,45 @@ BOOST_AUTO_TEST_CASE(parseX11RGB) BOOST_CHECK_CLOSE_VEC(parsedColours.at("slategrey"), AssetFactory::Colour(0.44F, 0.5, 0.56F)); BOOST_CHECK_CLOSE_VEC(parsedColours.at("lightsteelblue1"), AssetFactory::Colour(0.79, 0.88, 1)); } + +BOOST_AUTO_TEST_CASE(texturePacker) +{ + TexturePacker tp {{ + {10, 10}, + {10, 10}, + {10, 10}, + {100, 10}, + {10, 200}, + {5, 5}, + }}; + BOOST_CHECK_EQUAL(TexturePacker::Size(128, 256), tp.minSize()); + const auto result = tp.pack(); +} + +BOOST_AUTO_TEST_CASE(texturePacker_many, *boost::unit_test::timeout(5)) +{ + std::vector images(256); + std::fill(images.begin(), images.end(), TexturePacker::Image {32, 32}); + const auto totalSize = std::accumulate(images.begin(), images.end(), 0U, [](auto t, const auto & i) { + return t + TexturePacker::area(i); + }); + TexturePacker tp {images}; + BOOST_CHECK_EQUAL(TexturePacker::Size(32, 32), tp.minSize()); + const auto result = tp.pack(); + BOOST_CHECK_EQUAL(result.first.size(), images.size()); + BOOST_CHECK_GE(TexturePacker::area(result.second), TexturePacker::area(images.front()) * images.size()); + BOOST_CHECK_EQUAL(totalSize, TexturePacker::area(result.second)); +} + +BOOST_AUTO_TEST_CASE(texturePacker_many_random, *boost::unit_test::timeout(5)) +{ + std::vector images(2048); + std::mt19937 gen(std::random_device {}()); + std::uniform_int_distribution<> dim {1, 10}; + std::generate(images.begin(), images.end(), [&dim, &gen]() { + return TexturePacker::Image {2 ^ dim(gen), 2 ^ dim(gen)}; + }); + TexturePacker tp {images}; + const auto result = tp.pack(); + BOOST_CHECK_EQUAL(result.first.size(), images.size()); +} -- cgit v1.2.3 From c915f1bcd46144578fad464e52b5a6013dc98de8 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 17 Mar 2023 02:05:42 +0000 Subject: Fix texture packer return value so positions match inputs --- assetFactory/texturePacker.cpp | 15 +++++++++------ assetFactory/texturePacker.h | 5 +++-- test/test-assetFactory.cpp | 5 +++-- 3 files changed, 15 insertions(+), 10 deletions(-) (limited to 'test/test-assetFactory.cpp') diff --git a/assetFactory/texturePacker.cpp b/assetFactory/texturePacker.cpp index 31c9a0e..68a6010 100644 --- a/assetFactory/texturePacker.cpp +++ b/assetFactory/texturePacker.cpp @@ -1,14 +1,16 @@ #include "texturePacker.h" +#include "collections.hpp" #include #include #include #include #include -TexturePacker::TexturePacker(std::vector in) : inputImages {std::move(in)} +TexturePacker::TexturePacker(std::span in) : + inputImages {std::move(in)}, sortedIndexes {vectorOfN(inputImages.size(), size_t {})} { - std::sort(inputImages.rbegin(), inputImages.rend(), [](const auto & a, const auto & b) { - return area(a) < area(b); + std::sort(sortedIndexes.rbegin(), sortedIndexes.rend(), [this](const auto a, const auto b) { + return area(inputImages[a]) < area(inputImages[b]); }); } @@ -24,15 +26,16 @@ TexturePacker::pack(Size size) const using Spaces = std::set; Spaces spaces {{{}, size}}; - Positions result; - for (const auto & image : inputImages) { + Positions result(inputImages.size()); + for (const auto & idx : sortedIndexes) { + const auto & image = inputImages[idx]; if (const auto spaceItr = std::find_if(spaces.begin(), spaces.end(), [image](const Space & s) { return image.x <= s.size.x && image.y <= s.size.y; }); spaceItr != spaces.end()) { auto space = *spaceItr; - result.push_back(space.position); + result[idx] = space.position; spaces.erase(spaceItr); if (space.size.x > image.x) { spaces.emplace(Position {space.position.x + image.x, space.position.y}, diff --git a/assetFactory/texturePacker.h b/assetFactory/texturePacker.h index 8e2061b..7e00f1a 100644 --- a/assetFactory/texturePacker.h +++ b/assetFactory/texturePacker.h @@ -23,7 +23,7 @@ public: using Positions = std::vector; using Result = std::pair; - TexturePacker(std::vector); + TexturePacker(std::span); Result pack(Size) const; Result pack() const; @@ -32,5 +32,6 @@ public: static decltype(Size::x) area(const Size & size); private: - std::vector inputImages; + std::span inputImages; + std::vector sortedIndexes; }; diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp index ad62a93..d71fa9b 100644 --- a/test/test-assetFactory.cpp +++ b/test/test-assetFactory.cpp @@ -129,14 +129,15 @@ BOOST_AUTO_TEST_CASE(parseX11RGB) BOOST_AUTO_TEST_CASE(texturePacker) { - TexturePacker tp {{ + std::vector input { {10, 10}, {10, 10}, {10, 10}, {100, 10}, {10, 200}, {5, 5}, - }}; + }; + TexturePacker tp {input}; BOOST_CHECK_EQUAL(TexturePacker::Size(128, 256), tp.minSize()); const auto result = tp.pack(); } -- cgit v1.2.3 From b76ad768ceddc2777044d0f7128d292332a75353 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 7 Apr 2023 23:49:36 +0100 Subject: Add timeouts to asset factory tests Yes, I made some infinite loops a few times --- test/test-assetFactory.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test/test-assetFactory.cpp') diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp index d71fa9b..54168aa 100644 --- a/test/test-assetFactory.cpp +++ b/test/test-assetFactory.cpp @@ -68,7 +68,7 @@ private: }; BOOST_FIXTURE_TEST_SUITE(m, FactoryFixture); -BOOST_AUTO_TEST_CASE(brush47xml) +BOOST_AUTO_TEST_CASE(brush47xml, *boost::unit_test::timeout(5)) { auto mf = AssetFactory::loadXML(RESDIR "/brush47.xml"); BOOST_REQUIRE(mf); @@ -118,7 +118,7 @@ BOOST_DATA_TEST_CASE(normalizeColourName, BOOST_CHECK_EQUAL(in, exp); } -BOOST_AUTO_TEST_CASE(parseX11RGB) +BOOST_AUTO_TEST_CASE(parseX11RGB, *boost::unit_test::timeout(5)) { const auto parsedColours = AssetFactory::parseX11RGB(FIXTURESDIR "rgb.txt"); BOOST_REQUIRE_EQUAL(parsedColours.size(), 20); @@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE(parseX11RGB) BOOST_CHECK_CLOSE_VEC(parsedColours.at("lightsteelblue1"), AssetFactory::Colour(0.79, 0.88, 1)); } -BOOST_AUTO_TEST_CASE(texturePacker) +BOOST_AUTO_TEST_CASE(texturePacker, *boost::unit_test::timeout(5)) { std::vector input { {10, 10}, -- cgit v1.2.3