metaforce/specter/include/Specter/FontCache.hpp

210 lines
6.3 KiB
C++
Raw Normal View History

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
};
using FCharFilter = std::pair<std::string, std::function<bool(uint32_t)>>;
2015-11-28 21:45:38 +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-30 02:55:08 +00:00
boo::ITextureSA* m_tex = nullptr;
2015-12-08 05:41:30 +00:00
boo::IGraphicsDataToken m_token;
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-29 02:55:30 +00:00
FT_Pos m_lineHeight;
bool m_subpixel;
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;
2015-12-02 06:13:43 +00:00
atUint32 m_glyphIdx;
2015-11-23 08:47:21 +00:00
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;
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,
2015-11-28 21:45:38 +00:00
bool subpixel, FCharFilter& filter, Athena::io::FileWriter& writer);
2015-11-25 01:46:30 +00:00
FontAtlas(boo::IGraphicsDataFactory* gf, FT_Face face, uint32_t dpi,
2015-11-28 21:45:38 +00:00
bool subpixel, FCharFilter& filter, Athena::io::FileReader& reader);
2015-11-25 01:46:30 +00:00
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;}
2015-11-29 02:55:30 +00:00
FT_Pos FT_LineHeight() const {return m_lineHeight;}
2015-11-26 07:35:43 +00:00
boo::ITexture* texture() const {return m_tex;}
2015-11-29 02:55:30 +00:00
bool subpixel() const {return m_subpixel;}
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];
}
2015-12-02 06:13:43 +00:00
atInt16 lookupKern(atUint32 leftIdx, atUint32 rightIdx) const
2015-11-26 00:24:01 +00:00
{
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
};
static FCharFilter const AllCharFilter =
std::make_pair("all-glyphs", [](uint32_t)->bool
{return true;});
static FCharFilter const LatinCharFilter =
std::make_pair("latin-glyphs", [](uint32_t c)->bool
{return c <= 0xff || ((c - 0x2200) <= (0x23FF - 0x2200));});
static FCharFilter const LatinAndJapaneseCharFilter =
std::make_pair("latin-and-jp-glyphs", [](uint32_t c)->bool
2015-12-02 03:05:22 +00:00
{return LatinCharFilter.second(c) ||
((c - 0x2E00) <= (0x30FF - 0x2E00)) ||
((c - 0x4E00) <= (0x9FFF - 0x4E00)) ||
((c - 0xFF00) <= (0xFFEF - 0xFF00));});
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-12-07 00:52:07 +00:00
FreeTypeGZipMemFace m_curvesFace;
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-28 21:45:38 +00:00
FontTag prepCustomFont(boo::IGraphicsDataFactory* gf, const std::string& name, FT_Face face,
FCharFilter filter=AllCharFilter, bool subpixel=false,
2015-11-23 08:47:21 +00:00
float points=10.0, uint32_t dpi=72);
2015-11-23 23:28:32 +00:00
FontTag prepMainFont(boo::IGraphicsDataFactory* gf, FCharFilter filter=AllCharFilter,
2015-11-23 08:47:21 +00:00
bool subpixel=false, float points=10.0, uint32_t dpi=72)
2015-11-28 21:45:38 +00:00
{return prepCustomFont(gf, "droidsans-permissive", m_regFace, filter, subpixel, points, dpi);}
2015-11-23 23:28:32 +00:00
FontTag prepMonoFont(boo::IGraphicsDataFactory* gf, FCharFilter filter=AllCharFilter,
2015-11-23 08:47:21 +00:00
bool subpixel=false, float points=10.0, uint32_t dpi=72)
2015-11-28 21:45:38 +00:00
{return prepCustomFont(gf, "bmonofont", m_monoFace, filter, subpixel, points, dpi);}
2015-11-23 23:28:32 +00:00
2015-12-07 00:52:07 +00:00
FontTag prepCurvesFont(boo::IGraphicsDataFactory* gf, FCharFilter filter=AllCharFilter,
bool subpixel=false, float points=10.0, uint32_t dpi=72)
{return prepCustomFont(gf, "spectercurves", m_curvesFace, filter, subpixel, points, dpi);}
void closeBuiltinFonts() {m_regFace.close(); m_monoFace.close(); m_curvesFace.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