2015-11-21 23:45:02 +00:00
|
|
|
#ifndef SPECTER_FONTCACHE_HPP
|
|
|
|
#define SPECTER_FONTCACHE_HPP
|
|
|
|
|
|
|
|
#include <ft2build.h>
|
|
|
|
#include FT_FREETYPE_H
|
|
|
|
|
2015-11-22 04:32:12 +00:00
|
|
|
#include <boo/boo.hpp>
|
|
|
|
#include <HECL/Runtime.hpp>
|
2015-11-23 08:47:21 +00:00
|
|
|
#include <Athena/FileReader.hpp>
|
|
|
|
#include <Athena/FileWriter.hpp>
|
|
|
|
|
|
|
|
namespace Specter
|
|
|
|
{
|
|
|
|
class FontTag
|
|
|
|
{
|
|
|
|
friend class FontCache;
|
2015-11-26 07:35:43 +00:00
|
|
|
uint64_t m_hash = 0;
|
2015-11-23 08:47:21 +00:00
|
|
|
FontTag(const std::string& name, bool subpixel, float points, unsigned dpi);
|
|
|
|
public:
|
2015-11-26 07:35:43 +00:00
|
|
|
FontTag() = default;
|
|
|
|
operator bool() const {return m_hash != 0;}
|
2015-11-23 08:47:21 +00:00
|
|
|
uint64_t hash() const {return m_hash;}
|
|
|
|
bool operator==(const FontTag& other) const {return m_hash == other.m_hash;}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace std
|
|
|
|
{
|
|
|
|
template <> struct hash<Specter::FontTag>
|
|
|
|
{
|
|
|
|
size_t operator() (const Specter::FontTag& handle) const NOEXCEPT
|
|
|
|
{return size_t(handle.hash());}
|
|
|
|
};
|
|
|
|
}
|
2015-11-22 04:32:12 +00:00
|
|
|
|
2015-11-21 23:45:02 +00:00
|
|
|
namespace Specter
|
|
|
|
{
|
|
|
|
|
2015-11-22 22:30:42 +00:00
|
|
|
class FreeTypeGZipMemFace
|
|
|
|
{
|
2015-11-23 23:28:32 +00:00
|
|
|
FT_Library m_lib;
|
2015-11-22 22:30:42 +00:00
|
|
|
FT_StreamRec m_comp = {};
|
|
|
|
FT_StreamRec m_decomp = {};
|
2015-11-23 23:28:32 +00:00
|
|
|
FT_Face m_face = nullptr;
|
2015-11-22 22:30:42 +00:00
|
|
|
public:
|
|
|
|
FreeTypeGZipMemFace(FT_Library lib, const uint8_t* data, size_t sz);
|
2015-11-25 01:46:30 +00:00
|
|
|
FreeTypeGZipMemFace(const FreeTypeGZipMemFace& other) = delete;
|
|
|
|
FreeTypeGZipMemFace& operator=(const FreeTypeGZipMemFace& other) = delete;
|
2015-11-23 23:28:32 +00:00
|
|
|
~FreeTypeGZipMemFace() {close();}
|
|
|
|
void open();
|
|
|
|
void close();
|
|
|
|
operator FT_Face() {open(); return m_face;}
|
2015-11-22 22:30:42 +00:00
|
|
|
};
|
|
|
|
|
2015-11-22 04:32:12 +00:00
|
|
|
class FontAtlas
|
|
|
|
{
|
2015-11-23 08:47:21 +00:00
|
|
|
friend class FontCache;
|
2015-11-22 04:32:12 +00:00
|
|
|
FT_Face m_face;
|
2015-11-26 23:03:56 +00:00
|
|
|
boo::ITextureSA* m_tex;
|
2015-11-25 01:46:30 +00:00
|
|
|
uint32_t m_dpi;
|
2015-11-26 07:35:43 +00:00
|
|
|
FT_Fixed m_ftXscale;
|
|
|
|
FT_UShort m_ftXPpem;
|
2015-11-23 08:47:21 +00:00
|
|
|
|
2015-11-25 01:46:30 +00:00
|
|
|
public:
|
2015-11-23 08:47:21 +00:00
|
|
|
struct Glyph
|
|
|
|
{
|
|
|
|
atUint32 m_unicodePoint;
|
|
|
|
atUint32 m_layerIdx;
|
2015-11-26 00:24:01 +00:00
|
|
|
float m_layerFloat;
|
2015-11-23 08:47:21 +00:00
|
|
|
float m_uv[4];
|
2015-11-26 23:03:56 +00:00
|
|
|
atInt32 m_leftPadding;
|
|
|
|
atInt32 m_advance;
|
|
|
|
atInt32 m_rightPadding;
|
|
|
|
atUint32 m_width;
|
|
|
|
atUint32 m_height;
|
|
|
|
atInt32 m_verticalOffset;
|
2015-11-25 01:46:30 +00:00
|
|
|
};
|
|
|
|
|
2015-11-26 00:24:01 +00:00
|
|
|
private:
|
|
|
|
std::vector<Glyph> m_glyphs;
|
|
|
|
std::unordered_map<atUint16, std::vector<std::pair<atUint16, atInt16>>> m_kernAdjs;
|
|
|
|
|
|
|
|
struct TT_KernHead : Athena::io::DNA<Athena::BigEndian>
|
2015-11-25 01:46:30 +00:00
|
|
|
{
|
2015-11-26 00:24:01 +00:00
|
|
|
DECL_DNA
|
|
|
|
Value<atUint32> length;
|
|
|
|
Value<atUint16> coverage;
|
2015-11-23 08:47:21 +00:00
|
|
|
};
|
2015-11-25 01:46:30 +00:00
|
|
|
|
2015-11-26 00:24:01 +00:00
|
|
|
struct TT_KernSubHead : Athena::io::DNA<Athena::BigEndian>
|
|
|
|
{
|
|
|
|
DECL_DNA
|
|
|
|
Value<atUint16> nPairs;
|
|
|
|
Value<atUint16> searchRange;
|
|
|
|
Value<atUint16> entrySelector;
|
|
|
|
Value<atUint16> rangeShift;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct TT_KernPair : Athena::io::DNA<Athena::BigEndian>
|
|
|
|
{
|
|
|
|
DECL_DNA
|
|
|
|
Value<atUint16> left;
|
|
|
|
Value<atUint16> right;
|
|
|
|
Value<atInt16> value;
|
|
|
|
};
|
|
|
|
|
|
|
|
void buildKernTable(FT_Face face);
|
|
|
|
|
2015-11-25 01:46:30 +00:00
|
|
|
std::unordered_map<atUint32, size_t> m_glyphLookup;
|
2015-11-23 08:47:21 +00:00
|
|
|
|
|
|
|
public:
|
2015-11-25 01:46:30 +00:00
|
|
|
FontAtlas(boo::IGraphicsDataFactory* gf, FT_Face face, uint32_t dpi,
|
|
|
|
bool subpixel, Athena::io::FileWriter& writer);
|
|
|
|
FontAtlas(boo::IGraphicsDataFactory* gf, FT_Face face, uint32_t dpi,
|
|
|
|
bool subpixel, Athena::io::FileReader& reader);
|
|
|
|
FontAtlas(const FontAtlas& other) = delete;
|
|
|
|
FontAtlas& operator=(const FontAtlas& other) = delete;
|
|
|
|
|
|
|
|
uint32_t dpi() const {return m_dpi;}
|
2015-11-26 07:35:43 +00:00
|
|
|
FT_Fixed FT_Xscale() const {return m_ftXscale;}
|
|
|
|
FT_UShort FT_XPPem() const {return m_ftXPpem;}
|
|
|
|
boo::ITexture* texture() const {return m_tex;}
|
2015-11-26 00:24:01 +00:00
|
|
|
|
|
|
|
const Glyph* lookupGlyph(atUint32 charcode) const
|
|
|
|
{
|
|
|
|
auto search = m_glyphLookup.find(charcode);
|
|
|
|
if (search == m_glyphLookup.end())
|
|
|
|
return nullptr;
|
|
|
|
return &m_glyphs[search->second];
|
|
|
|
}
|
|
|
|
atInt16 lookupKern(atUint32 left, atUint32 right) const
|
|
|
|
{
|
|
|
|
auto leftSearch = m_glyphLookup.find(left);
|
|
|
|
if (leftSearch == m_glyphLookup.cend())
|
|
|
|
return 0;
|
|
|
|
size_t leftIdx = leftSearch->second;
|
|
|
|
auto rightSearch = m_glyphLookup.find(right);
|
|
|
|
if (rightSearch == m_glyphLookup.cend())
|
|
|
|
return 0;
|
|
|
|
size_t rightIdx = rightSearch->second;
|
|
|
|
auto pairSearch = m_kernAdjs.find(leftIdx);
|
|
|
|
if (pairSearch == m_kernAdjs.cend())
|
|
|
|
return 0;
|
|
|
|
for (const std::pair<atUint16, atInt16>& p : pairSearch->second)
|
|
|
|
if (p.first == rightIdx)
|
|
|
|
return p.second;
|
|
|
|
return 0;
|
|
|
|
}
|
2015-11-22 04:32:12 +00:00
|
|
|
};
|
|
|
|
|
2015-11-21 23:45:02 +00:00
|
|
|
class FontCache
|
|
|
|
{
|
2015-11-22 04:32:12 +00:00
|
|
|
const HECL::Runtime::FileStoreManager& m_fileMgr;
|
2015-11-23 08:47:21 +00:00
|
|
|
HECL::SystemString m_cacheRoot;
|
2015-11-22 23:51:44 +00:00
|
|
|
struct Library
|
|
|
|
{
|
|
|
|
FT_Library m_lib;
|
|
|
|
Library();
|
|
|
|
~Library();
|
|
|
|
operator FT_Library() {return m_lib;}
|
|
|
|
} m_fontLib;
|
2015-11-22 22:30:42 +00:00
|
|
|
FreeTypeGZipMemFace m_regFace;
|
|
|
|
FreeTypeGZipMemFace m_monoFace;
|
2015-11-23 08:47:21 +00:00
|
|
|
|
|
|
|
std::unordered_map<FontTag, std::unique_ptr<FontAtlas>> m_cachedAtlases;
|
2015-11-22 04:32:12 +00:00
|
|
|
public:
|
|
|
|
FontCache(const HECL::Runtime::FileStoreManager& fileMgr);
|
2015-11-25 01:46:30 +00:00
|
|
|
FontCache(const FontCache& other) = delete;
|
|
|
|
FontCache& operator=(const FontCache& other) = delete;
|
2015-11-22 04:32:12 +00:00
|
|
|
|
2015-11-23 08:47:21 +00:00
|
|
|
FontTag prepCustomFont(boo::IGraphicsDataFactory* gf,
|
|
|
|
const std::string& name, FT_Face face, bool subpixel=false,
|
|
|
|
float points=10.0, uint32_t dpi=72);
|
2015-11-23 23:28:32 +00:00
|
|
|
|
2015-11-23 08:47:21 +00:00
|
|
|
FontTag prepMainFont(boo::IGraphicsDataFactory* gf,
|
|
|
|
bool subpixel=false, float points=10.0, uint32_t dpi=72)
|
|
|
|
{return prepCustomFont(gf, "droidsans-permissive", m_regFace, subpixel, points, dpi);}
|
2015-11-23 23:28:32 +00:00
|
|
|
|
2015-11-23 08:47:21 +00:00
|
|
|
FontTag prepMonoFont(boo::IGraphicsDataFactory* gf,
|
|
|
|
bool subpixel=false, float points=10.0, uint32_t dpi=72)
|
|
|
|
{return prepCustomFont(gf, "bmonofont", m_monoFace, subpixel, points, dpi);}
|
2015-11-23 23:28:32 +00:00
|
|
|
|
|
|
|
void closeBuiltinFonts() {m_regFace.close(); m_monoFace.close();}
|
2015-11-25 01:46:30 +00:00
|
|
|
|
|
|
|
const FontAtlas& lookupAtlas(FontTag tag) const;
|
2015-11-21 23:45:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // SPECTER_FONTCACHE_HPP
|