EHS/src/io/FontAtlas.cpp

304 lines
6.2 KiB
C++
Raw Normal View History

2024-02-05 22:25:30 -08:00
#include "ehs/io/FontAtlas.h"
#include "ehs/io/File.h"
#include "ehs/Serializer.h"
namespace ehs
{
FontAtlas::~FontAtlas()
{
delete[] atlas;
}
FontAtlas::FontAtlas()
: hashId(0), glyphScale(0), size(0), atlas(nullptr)
{
}
FontAtlas::FontAtlas(const Str_8& filePath)
{
File fontFile(filePath, Mode::READ, Disposition::OPEN);
hashId = fontFile.GetName().Hash_64();
id = fontFile.GetName();
Serializer<UInt_64> fData = fontFile.ReadSerializer_64(Endianness::LE, fontFile.Size());
fontFile.Release();
Version ver = fData.ReadVersion();
if (ver != Version(1, 0, 0))
{
EHS_LOG_INT(LogType::ERR, 2, "The Event Horizon Font file, \"" + filePath + "\", must be version 1.0.0, but was version " +
2024-02-05 22:25:30 -08:00
Str_8::FromNum(ver.major) + "." + Str_8::FromNum(ver.minor) + "." +
Str_8::FromNum(ver.patch) + ".");
return;
}
glyphScale = fData.Read<UInt_64>();
glyphs.Resize(fData.Read<UInt_64>());
for (UInt_64 i = 0; i < glyphs.Size(); ++i)
glyphs[i] = Glyph(fData);
resolution = fData.ReadVec2<UInt_64>();
atlas = new Byte[resolution.x * resolution.y];
size = 0;
2024-02-05 22:25:30 -08:00
fData.ReadArray(atlas, &size);
}
FontAtlas::FontAtlas(FontAtlas&& fa) noexcept
: BaseObj(std::move(fa)), hashId(fa.hashId), id((Str_8&&)fa.id), glyphScale(fa.glyphScale),
glyphs((Array<Glyph>&&)fa.glyphs), resolution(fa.resolution), size(fa.size), atlas(fa.atlas)
{
fa.hashId = 0;
fa.glyphScale = 0;
fa.resolution = {};
fa.size = 0;
fa.atlas = nullptr;
}
FontAtlas::FontAtlas(const FontAtlas& fa)
: BaseObj(fa), hashId(fa.hashId), id(fa.id), glyphScale(fa.glyphScale), glyphs(fa.glyphs),
resolution(fa.resolution), size(fa.size), atlas(new Byte[fa.size])
{
Util::Copy(atlas, fa.atlas, fa.size);
}
FontAtlas& FontAtlas::operator=(FontAtlas&& fa) noexcept
{
if (this == &fa)
return *this;
BaseObj::operator=(std::move(fa));
hashId = fa.hashId;
id = (Str_8&&)fa.id;
glyphScale = fa.glyphScale;
glyphs = (Array<Glyph>&&)fa.glyphs;
resolution = fa.resolution;
size = fa.size;
delete[] atlas;
atlas = fa.atlas;
fa.hashId = 0;
fa.glyphScale = 0;
fa.resolution = {};
fa.size = 0;
fa.atlas = nullptr;
return *this;
}
FontAtlas& FontAtlas::operator=(const FontAtlas& fa)
{
if (this == &fa)
return *this;
BaseObj::operator=(fa);
hashId = fa.hashId;
id = fa.id;
glyphScale = fa.glyphScale;
glyphs = fa.glyphs;
resolution = {};
size = fa.size;
delete[] atlas;
atlas = new Byte[fa.size];
Util::Copy(atlas, fa.atlas, fa.size);
return *this;
}
FontAtlas::operator Byte *() const
{
return atlas;
}
void FontAtlas::Release()
{
hashId = 0;
id = {};
glyphScale = 0;
glyphs.Clear();
resolution = {0, 0};
size = 0;
delete[] atlas;
atlas = nullptr;
}
UInt_64 FontAtlas::GetHashId() const
{
return hashId;
}
Str_8 FontAtlas::GetId() const
{
return id;
}
UInt_64 FontAtlas::GetGlyphScale() const
{
return glyphScale;
}
const Array<Glyph>& FontAtlas::GetGlyphs() const
{
return glyphs;
}
Glyph FontAtlas::GetGlyph(const Char_32 code) const
{
for (UInt_32 i = 0; i < glyphs.Size(); ++i)
if (glyphs[i].GetCode() == code)
return glyphs[i];
return glyphs[0];
}
Vec2_u64 FontAtlas::GetResolution() const
{
return resolution;
}
UInt_64 FontAtlas::GetSize() const
{
return size;
}
bool FontAtlas::IsValid() const
{
return size;
}
Vec2_f FontAtlas::CalculateSize(const Str_8& text) const
{
Vec2_f result;
for (UInt_64 i = 0; i < text.Size(); ++i)
{
Glyph glyph = GetGlyph(text[i]);
result.x += (float)glyph.GetAdvance().x;
if ((float)glyph.GetScale().y > result.y)
result.y = (float)glyph.GetScale().y;
}
return result;
}
float FontAtlas::CalculateWidth(const Str_8 &text) const
{
float result = 0.0f;
for (UInt_64 i = 0; i < text.Size(); ++i)
{
Glyph glyph = GetGlyph(text[i]);
result += (float)glyph.GetAdvance().x;
}
return result;
}
float FontAtlas::CalculateHeight(const Str_8& text) const
{
float result = 0.0f;
for (UInt_64 i = 0; i < text.Size(); ++i)
{
Glyph glyph = GetGlyph(text[i]);
if ((float)glyph.GetScale().y > result)
result = (float)glyph.GetScale().y;
}
return result;
}
UInt_64 FontAtlas::CalculateIndexAtPoint(const Str_8& text, const Vec2_f& point) const
{
float result = 0.0f;
for (UInt_64 i = 0; i < text.Size(); ++i)
{
Glyph glyph = GetGlyph(text[i]);
float temp = result + (float)glyph.GetAdvance().x;
if (point.x > temp)
result += (float)glyph.GetAdvance().x;
else if (point.x <= temp)
return i;
}
return text.Size();
}
Mesh FontAtlas::Generate(const Anchor anchor, const Str_8& text) const
{
Vec2_f pos;
switch (anchor)
{
case Anchor::BOTTOM_CENTER:
{
pos.x -= CalculateWidth(text) * 0.5f;
break;
}
case Anchor::TOP_LEFT:
{
pos.x -= CalculateWidth(text);
break;
}
case Anchor::TOP_CENTER:
{
pos.x -= CalculateWidth(text) * 0.5f;
break;
}
case Anchor::CENTER_RIGHT:
{
pos.y -= CalculateHeight(text);
break;
}
case Anchor::CENTER:
{
Vec4_f size = CalculateSize(text);
pos.x -= size.x * 0.5f;
pos.y -= size.y;
break;
}
}
Array<Vertex_f> verts(text.Size() * 4);
Array<UInt_32> indices(text.Size() * 6);
for (UInt_64 i = 0; i < text.Size(); ++i)
{
Glyph glyph = GetGlyph(text[i]);
Vec2_f scale = glyph.GetScale();
float x = pos.x + (float)glyph.GetBearing().x;
float y = pos.y + (float)(GetGlyphScale() - glyph.GetBearing().y);
UInt_32 vertsI = i * 4;
verts[vertsI] = Vertex_f({x, y, 1.0f}, {}, glyph.GetUV().GetPos());
verts[vertsI + 1] = Vertex_f({x, y + scale.y, 1.0f}, {}, Vec2_f(glyph.GetUV().x, glyph.GetUV().h));
verts[vertsI + 2] = Vertex_f({x + scale.x, y, 1.0f}, {}, Vec2_f(glyph.GetUV().w, glyph.GetUV().y));
verts[vertsI + 3] = Vertex_f({x + scale.x, y + scale.y, 1.0f}, {}, glyph.GetUV().GetScale());
UInt_32 indicesI = i * 6;
indices[indicesI] = vertsI;
indices[indicesI + 1] = vertsI + 1;
indices[indicesI + 2] = vertsI + 2;
indices[indicesI + 3] = vertsI + 3;
indices[indicesI + 4] = vertsI + 2;
indices[indicesI + 5] = vertsI + 1;
pos.x += (float)glyph.GetAdvance().x;
}
return {id, (Array<Vertex_f>&&)verts, (Array<UInt_32>&&)indices};
}
}