mirror of
https://github.com/NoelFB/blah.git
synced 2024-11-25 16:18:57 +08:00
spritefont uses a binary search instead of std::unordered_map
This commit is contained in:
parent
c13759f362
commit
51e80ec6a2
|
@ -5,7 +5,6 @@
|
|||
#include <blah/graphics/subtexture.h>
|
||||
#include <blah/numerics/spatial.h>
|
||||
#include <blah/filesystem.h>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Blah
|
||||
{
|
||||
|
@ -42,11 +41,20 @@ namespace Blah
|
|||
// Character Entry
|
||||
struct Character
|
||||
{
|
||||
Codepoint codepoint = 0;
|
||||
int glyph = 0;
|
||||
Subtexture subtexture;
|
||||
float advance = 0;
|
||||
Vec2f offset;
|
||||
};
|
||||
|
||||
struct Kerning
|
||||
{
|
||||
Codepoint a;
|
||||
Codepoint b;
|
||||
float value;
|
||||
};
|
||||
|
||||
// SpriteFont name
|
||||
String name;
|
||||
|
||||
|
@ -119,14 +127,8 @@ namespace Blah
|
|||
const Character& operator[](Codepoint codepoint) const;
|
||||
|
||||
private:
|
||||
// character set
|
||||
std::unordered_map<Codepoint, Character> m_characters;
|
||||
|
||||
// kerning
|
||||
// key is 2 codepoints combined ((first << 32) | second)
|
||||
std::unordered_map<u64, float> m_kerning;
|
||||
|
||||
// built texture
|
||||
Vector<Character> m_characters;
|
||||
Vector<Kerning> m_kerning;
|
||||
Vector<TextureRef> m_atlas;
|
||||
};
|
||||
}
|
|
@ -192,7 +192,6 @@ void SpriteFont::rebuild(const Font& font, float size, const CharSet& charset)
|
|||
packer.max_size = 8192;
|
||||
packer.power_of_two = true;
|
||||
|
||||
std::unordered_map<Codepoint, int> glyphs;
|
||||
Vector<Color> buffer;
|
||||
|
||||
for (auto& range : charset)
|
||||
|
@ -208,12 +207,12 @@ void SpriteFont::rebuild(const Font& font, float size, const CharSet& charset)
|
|||
if (glyph <= 0)
|
||||
continue;
|
||||
|
||||
glyphs[i] = glyph;
|
||||
|
||||
// add character
|
||||
auto ch = font.get_character(glyph, scale);
|
||||
m_characters[i].advance = ch.advance;
|
||||
m_characters[i].offset = Vec2f(ch.offset_x, ch.offset_y);
|
||||
auto& sfch = get_character(i);
|
||||
sfch.codepoint = i;
|
||||
sfch.advance = ch.advance;
|
||||
sfch.offset = Vec2f(ch.offset_x, ch.offset_y);
|
||||
|
||||
// pack glyph
|
||||
if (ch.has_glyph)
|
||||
|
@ -236,66 +235,138 @@ void SpriteFont::rebuild(const Font& font, float size, const CharSet& charset)
|
|||
// add character subtextures
|
||||
for (auto& it : packer.entries())
|
||||
if (!it.empty)
|
||||
m_characters[(Codepoint)it.id].subtexture = Subtexture(m_atlas[it.page], it.packed, it.frame);
|
||||
get_character((Codepoint)it.id).subtexture = Subtexture(m_atlas[it.page], it.packed, it.frame);
|
||||
|
||||
// add kerning
|
||||
for (auto a = glyphs.begin(); a != glyphs.end(); a++)
|
||||
for (auto b = glyphs.begin(); b != glyphs.end(); b++)
|
||||
{
|
||||
auto kern = font.get_kerning(a->second, b->second, scale);
|
||||
if (kern != 0)
|
||||
set_kerning(a->first, b->first, kern);
|
||||
}
|
||||
}
|
||||
|
||||
float SpriteFont::get_kerning(Codepoint codepoint0, Codepoint codepoint1) const
|
||||
{
|
||||
u64 index = ((u64)codepoint0 << 32) | codepoint1;
|
||||
|
||||
auto it = m_kerning.find(index);
|
||||
if (it != m_kerning.end())
|
||||
return it->second;
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void SpriteFont::set_kerning(Codepoint codepoint0, Codepoint codepoint1, float value)
|
||||
{
|
||||
u64 index = ((u64)codepoint0 << 32) | codepoint1;
|
||||
|
||||
if (value == 0)
|
||||
for (auto& a : m_characters)
|
||||
{
|
||||
m_kerning.erase(index);
|
||||
for (auto& b : m_characters)
|
||||
{
|
||||
auto kerning_value = font.get_kerning(a.glyph, b.glyph, scale);
|
||||
if (kerning_value != 0)
|
||||
set_kerning(a.codepoint, b.codepoint, kerning_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
bool find_character_index(const Vector<SpriteFont::Character>& items, SpriteFont::Codepoint codepoint, int lower, int higher, int* index)
|
||||
{
|
||||
while (lower <= higher)
|
||||
{
|
||||
// found
|
||||
int mid = (higher + lower) / 2;
|
||||
if (items[mid].codepoint == codepoint)
|
||||
{
|
||||
*index = mid;
|
||||
return true;
|
||||
}
|
||||
|
||||
// search upper / lower bounds
|
||||
if (items[mid].codepoint < codepoint)
|
||||
lower = mid + 1;
|
||||
else
|
||||
higher = mid - 1;
|
||||
}
|
||||
|
||||
// not found
|
||||
*index = lower;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool find_kerning_index(const Vector<SpriteFont::Kerning>& items, SpriteFont::Codepoint a, SpriteFont::Codepoint b, int lower, int higher, int* index)
|
||||
{
|
||||
while (lower <= higher)
|
||||
{
|
||||
// found
|
||||
int mid = (higher + lower) / 2;
|
||||
if (items[mid].a == a && items[mid].b == b)
|
||||
{
|
||||
*index = mid;
|
||||
return true;
|
||||
}
|
||||
|
||||
// search upper / lower bounds
|
||||
if (items[mid].a == a)
|
||||
{
|
||||
if (items[mid].b < b)
|
||||
lower = mid + 1;
|
||||
else
|
||||
higher = mid - 1;
|
||||
}
|
||||
else if (items[mid].a < a)
|
||||
lower = mid + 1;
|
||||
else
|
||||
higher = mid - 1;
|
||||
}
|
||||
|
||||
// not found
|
||||
*index = lower;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
float SpriteFont::get_kerning(Codepoint a, Codepoint b) const
|
||||
{
|
||||
int index;
|
||||
if (find_kerning_index(m_kerning, a, b, 0, m_kerning.size() - 1, &index))
|
||||
return m_kerning[index].value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SpriteFont::set_kerning(Codepoint a, Codepoint b, float value)
|
||||
{
|
||||
int index;
|
||||
if (find_kerning_index(m_kerning, a, b, 0, m_kerning.size() - 1, &index))
|
||||
{
|
||||
m_kerning[index].value = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_kerning[index] = value;
|
||||
m_kerning.expand();
|
||||
for (int i = m_kerning.size() - 1; i > index; i--)
|
||||
m_kerning[i] = std::move(m_kerning[i - 1]);
|
||||
m_kerning[index].a = a;
|
||||
m_kerning[index].b = b;
|
||||
m_kerning[index].value = value;
|
||||
}
|
||||
}
|
||||
|
||||
SpriteFont::Character& SpriteFont::get_character(Codepoint codepoint)
|
||||
{
|
||||
return m_characters[codepoint];
|
||||
int index;
|
||||
if (find_character_index(m_characters, codepoint, 0, m_characters.size() - 1, &index))
|
||||
{
|
||||
return m_characters[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
m_characters.expand();
|
||||
for (int i = m_characters.size() - 1; i > index; i --)
|
||||
m_characters[i] = std::move(m_characters[i - 1]);
|
||||
m_characters[index].codepoint = codepoint;
|
||||
return m_characters[index];
|
||||
}
|
||||
}
|
||||
|
||||
const SpriteFont::Character& SpriteFont::get_character(Codepoint codepoint) const
|
||||
{
|
||||
static const Character empty;
|
||||
auto it = m_characters.find(codepoint);
|
||||
if (it != m_characters.end())
|
||||
return it->second;
|
||||
|
||||
int index;
|
||||
if (find_character_index(m_characters, codepoint, 0, m_characters.size() - 1, &index))
|
||||
return m_characters[index];
|
||||
|
||||
return empty;
|
||||
}
|
||||
|
||||
SpriteFont::Character& SpriteFont::operator[](Codepoint codepoint)
|
||||
{
|
||||
return m_characters[codepoint];
|
||||
return get_character(codepoint);
|
||||
}
|
||||
|
||||
const SpriteFont::Character& SpriteFont::operator[](Codepoint codepoint) const
|
||||
{
|
||||
static const Character empty;
|
||||
auto it = m_characters.find(codepoint);
|
||||
if (it != m_characters.end())
|
||||
return it->second;
|
||||
return empty;
|
||||
return get_character(codepoint);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user