Utility/GuillotineImageAtlas: Add max layer size
This commit is contained in:
parent
fe16584c8c
commit
86cc814f1b
|
|
@ -29,6 +29,7 @@ namespace Nz
|
||||||
|
|
||||||
void Free(SparsePtr<const Rectui> rects, SparsePtr<unsigned int> layers, unsigned int count) override;
|
void Free(SparsePtr<const Rectui> rects, SparsePtr<unsigned int> layers, unsigned int count) override;
|
||||||
|
|
||||||
|
unsigned int GetMaxLayerSize() const;
|
||||||
GuillotineBinPack::FreeRectChoiceHeuristic GetRectChoiceHeuristic() const;
|
GuillotineBinPack::FreeRectChoiceHeuristic GetRectChoiceHeuristic() const;
|
||||||
GuillotineBinPack::GuillotineSplitHeuristic GetRectSplitHeuristic() const;
|
GuillotineBinPack::GuillotineSplitHeuristic GetRectSplitHeuristic() const;
|
||||||
AbstractImage* GetLayer(unsigned int layerIndex) const override;
|
AbstractImage* GetLayer(unsigned int layerIndex) const override;
|
||||||
|
|
@ -37,6 +38,7 @@ namespace Nz
|
||||||
|
|
||||||
bool Insert(const Image& image, Rectui* rect, bool* flipped, unsigned int* layerIndex) override;
|
bool Insert(const Image& image, Rectui* rect, bool* flipped, unsigned int* layerIndex) override;
|
||||||
|
|
||||||
|
void SetMaxLayerSize(unsigned int maxLayerSize);
|
||||||
void SetRectChoiceHeuristic(GuillotineBinPack::FreeRectChoiceHeuristic heuristic);
|
void SetRectChoiceHeuristic(GuillotineBinPack::FreeRectChoiceHeuristic heuristic);
|
||||||
void SetRectSplitHeuristic(GuillotineBinPack::GuillotineSplitHeuristic heuristic);
|
void SetRectSplitHeuristic(GuillotineBinPack::GuillotineSplitHeuristic heuristic);
|
||||||
|
|
||||||
|
|
@ -70,6 +72,7 @@ namespace Nz
|
||||||
mutable std::vector<Layer> m_layers;
|
mutable std::vector<Layer> m_layers;
|
||||||
GuillotineBinPack::FreeRectChoiceHeuristic m_rectChoiceHeuristic;
|
GuillotineBinPack::FreeRectChoiceHeuristic m_rectChoiceHeuristic;
|
||||||
GuillotineBinPack::GuillotineSplitHeuristic m_rectSplitHeuristic;
|
GuillotineBinPack::GuillotineSplitHeuristic m_rectSplitHeuristic;
|
||||||
|
unsigned int m_maxLayerSize;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,8 @@ namespace Nz
|
||||||
|
|
||||||
GuillotineImageAtlas::GuillotineImageAtlas() :
|
GuillotineImageAtlas::GuillotineImageAtlas() :
|
||||||
m_rectChoiceHeuristic(GuillotineBinPack::RectBestAreaFit),
|
m_rectChoiceHeuristic(GuillotineBinPack::RectBestAreaFit),
|
||||||
m_rectSplitHeuristic(GuillotineBinPack::SplitMinimizeArea)
|
m_rectSplitHeuristic(GuillotineBinPack::SplitMinimizeArea),
|
||||||
|
m_maxLayerSize(16384)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,6 +43,11 @@ namespace Nz
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int GuillotineImageAtlas::GetMaxLayerSize() const
|
||||||
|
{
|
||||||
|
return m_maxLayerSize;
|
||||||
|
}
|
||||||
|
|
||||||
GuillotineBinPack::FreeRectChoiceHeuristic GuillotineImageAtlas::GetRectChoiceHeuristic() const
|
GuillotineBinPack::FreeRectChoiceHeuristic GuillotineImageAtlas::GetRectChoiceHeuristic() const
|
||||||
{
|
{
|
||||||
return m_rectChoiceHeuristic;
|
return m_rectChoiceHeuristic;
|
||||||
|
|
@ -115,9 +121,10 @@ namespace Nz
|
||||||
if (newSize == Vector2ui::Zero())
|
if (newSize == Vector2ui::Zero())
|
||||||
newSize.Set(s_atlasStartSize);
|
newSize.Set(s_atlasStartSize);
|
||||||
|
|
||||||
if (ResizeLayer(layer, newSize))
|
// Limit image atlas size to prevent allocating too much contiguous memory blocks
|
||||||
|
if (newSize.x <= m_maxLayerSize && newSize.y <= m_maxLayerSize && ResizeLayer(layer, newSize))
|
||||||
{
|
{
|
||||||
// Oui on peut !
|
// Yes we can!
|
||||||
layer.binPack.Expand(newSize); // On ajuste l'atlas virtuel
|
layer.binPack.Expand(newSize); // On ajuste l'atlas virtuel
|
||||||
|
|
||||||
// Et on relance la boucle sur la nouvelle dernière couche
|
// Et on relance la boucle sur la nouvelle dernière couche
|
||||||
|
|
@ -149,6 +156,11 @@ namespace Nz
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GuillotineImageAtlas::SetMaxLayerSize(unsigned int maxLayerSize)
|
||||||
|
{
|
||||||
|
m_maxLayerSize = maxLayerSize;
|
||||||
|
}
|
||||||
|
|
||||||
void GuillotineImageAtlas::SetRectChoiceHeuristic(GuillotineBinPack::FreeRectChoiceHeuristic heuristic)
|
void GuillotineImageAtlas::SetRectChoiceHeuristic(GuillotineBinPack::FreeRectChoiceHeuristic heuristic)
|
||||||
{
|
{
|
||||||
m_rectChoiceHeuristic = heuristic;
|
m_rectChoiceHeuristic = heuristic;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
|
#include <Nazara/Utility/AbstractImage.hpp>
|
||||||
#include <Nazara/Utility/Font.hpp>
|
#include <Nazara/Utility/Font.hpp>
|
||||||
|
#include <Nazara/Utility/GuillotineImageAtlas.hpp>
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch.hpp>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
@ -11,6 +13,11 @@ SCENARIO("Fonts", "[Utility][Font]")
|
||||||
{
|
{
|
||||||
std::shared_ptr<Nz::Font> font = Nz::Font::GetDefault();
|
std::shared_ptr<Nz::Font> font = Nz::Font::GetDefault();
|
||||||
|
|
||||||
|
std::shared_ptr<Nz::GuillotineImageAtlas> imageAtlas = std::make_shared<Nz::GuillotineImageAtlas>();
|
||||||
|
imageAtlas->SetMaxLayerSize(1024);
|
||||||
|
|
||||||
|
font->SetAtlas(imageAtlas);
|
||||||
|
|
||||||
CHECK(font->GetFamilyName() == "Open Sans");
|
CHECK(font->GetFamilyName() == "Open Sans");
|
||||||
CHECK(font->GetStyleName() == "Regular");
|
CHECK(font->GetStyleName() == "Regular");
|
||||||
|
|
||||||
|
|
@ -72,28 +79,65 @@ SCENARIO("Fonts", "[Utility][Font]")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WHEN("Retrieving a glyph existing in the font")
|
WHEN("Retrieving glyphs")
|
||||||
{
|
{
|
||||||
const auto& glyph = font->GetGlyph(72, Nz::TextStyle_Regular, 0.f, 'L');
|
const auto& glyph1 = font->GetGlyph(72, Nz::TextStyle_Regular, 0.f, 'L');
|
||||||
REQUIRE(glyph.valid);
|
REQUIRE(glyph1.valid);
|
||||||
CHECK(glyph.advance == 37);
|
CHECK(glyph1.advance == 37);
|
||||||
CHECK(glyph.aabb.IsValid());
|
CHECK(glyph1.aabb.IsValid());
|
||||||
CHECK(glyph.atlasRect.IsValid());
|
CHECK(glyph1.atlasRect.IsValid());
|
||||||
CHECK(glyph.fauxOutlineThickness == 0.f);
|
CHECK(glyph1.fauxOutlineThickness == 0.f);
|
||||||
CHECK_FALSE(glyph.requireFauxBold);
|
CHECK_FALSE(glyph1.requireFauxBold);
|
||||||
CHECK_FALSE(glyph.requireFauxItalic);
|
CHECK_FALSE(glyph1.requireFauxItalic);
|
||||||
|
|
||||||
|
const auto& glyphYItalic = font->GetGlyph(72, Nz::TextStyle::Italic, 0.f, 'y');
|
||||||
|
REQUIRE(glyphYItalic.valid);
|
||||||
|
CHECK(glyphYItalic.advance == 36);
|
||||||
|
CHECK(glyphYItalic.aabb.IsValid());
|
||||||
|
CHECK(glyphYItalic.atlasRect.IsValid());
|
||||||
|
CHECK(glyphYItalic.fauxOutlineThickness == 0.f);
|
||||||
|
CHECK_FALSE(glyphYItalic.requireFauxBold);
|
||||||
|
CHECK(glyphYItalic.requireFauxItalic);
|
||||||
|
|
||||||
|
const auto& glyphYRegular = font->GetGlyph(72, Nz::TextStyle_Regular, 0.f, 'y');
|
||||||
|
REQUIRE(glyphYRegular.valid);
|
||||||
|
CHECK(glyphYRegular.advance == 36);
|
||||||
|
CHECK(glyphYRegular.aabb == glyphYItalic.aabb);
|
||||||
|
CHECK(glyphYRegular.atlasRect == glyphYItalic.atlasRect);
|
||||||
|
CHECK(glyphYRegular.fauxOutlineThickness == 0.f);
|
||||||
|
CHECK_FALSE(glyphYRegular.requireFauxBold);
|
||||||
|
CHECK_FALSE(glyphYRegular.requireFauxItalic);
|
||||||
|
|
||||||
|
CHECK(font->GetCachedGlyphCount() == 3);
|
||||||
|
CHECK(font->GetAtlas()->GetLayerCount() == 1);
|
||||||
|
CHECK(font->GetAtlas()->GetLayer(0)->GetLevelCount() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
WHEN("Retrieving a glyph existing in the font with italic")
|
WHEN("Precaching a lot of glyphs")
|
||||||
{
|
{
|
||||||
const auto& glyph = font->GetGlyph(72, Nz::TextStyle::Italic, 0.f, 'y');
|
std::string characterSet;
|
||||||
REQUIRE(glyph.valid);
|
for (char c = 'a'; c <= 'z'; ++c)
|
||||||
CHECK(glyph.advance == 36);
|
characterSet += c;
|
||||||
CHECK(glyph.aabb.IsValid());
|
|
||||||
CHECK(glyph.atlasRect.IsValid());
|
for (char c = 'A'; c <= 'Z'; ++c)
|
||||||
CHECK(glyph.fauxOutlineThickness == 0.f);
|
characterSet += c;
|
||||||
CHECK_FALSE(glyph.requireFauxBold);
|
|
||||||
CHECK(glyph.requireFauxItalic);
|
for (char c = '0'; c <= '9'; ++c)
|
||||||
|
characterSet += c;
|
||||||
|
|
||||||
|
for (unsigned int fontSize : {24, 36, 48, 72, 140})
|
||||||
|
{
|
||||||
|
for (float outlineThickness : { 0.f, 1.f, 2.f, 5.f })
|
||||||
|
{
|
||||||
|
font->Precache(fontSize, Nz::TextStyle_Regular, outlineThickness, characterSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(font->GetAtlas()->GetLayerCount() > 1);
|
||||||
|
for (std::size_t layerIndex = 0; layerIndex < font->GetAtlas()->GetLayerCount(); ++layerIndex)
|
||||||
|
{
|
||||||
|
CHECK(font->GetAtlas()->GetLayer(layerIndex)->GetLevelCount() == 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == 1)
|
if (i == 1)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue