Created
May 15, 2021 16:00
-
-
Save JonathanCline/6e5400900605e348f4f15d7e0fed91d9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #pragma once | |
| #include <SAEEngine_Components.h> | |
| #include <glm/gtc/matrix_transform.hpp> | |
| #include <glm/gtc/quaternion.hpp> | |
| #include <cstdint> | |
| #include <filesystem> | |
| #include <unordered_map> | |
| #include <string> | |
| #include <memory> | |
| #include <map> | |
| #include <concepts> | |
| #include <type_traits> | |
| #include <array> | |
| #include <functional> | |
| #include <numeric> | |
| #include <istream> | |
| #include <ostream> | |
| #define SAE_ENGINE_TEXT_NAMESPACE SAE_ENGINE_NAMESPACE | |
| namespace SAE_ENGINE_TEXT_NAMESPACE | |
| { | |
| /** | |
| * @brief Default character type. Type aliases like glyph_string use this type as the CharT parameter. | |
| */ | |
| using default_character_t = char; | |
| /** | |
| * @brief concept is true if type is an integral character type (char8_t, char16_t, char32_t, char, wchar_t) | |
| */ | |
| template <typename T> | |
| concept cx_character = | |
| std::is_same<T, char8_t>::value || | |
| std::is_same<T, char16_t>::value || | |
| std::is_same<T, char32_t>::value || | |
| std::is_same<T, char>::value || | |
| std::is_same<T, wchar_t>::value;; | |
| struct glyph_color; | |
| struct glyph_format; | |
| struct glyph_texture; | |
| using glyph_texcoords = texture_sheet::texcoords; | |
| template <cx_character CharT> | |
| struct basic_glyph; | |
| template <cx_character CharT> | |
| struct basic_glyph_instance; | |
| template <cx_character CharT> | |
| struct basic_typeface; | |
| template <cx_character CharT> | |
| struct basic_font; | |
| template <cx_character CharT> | |
| struct basic_glyph_string; | |
| /** | |
| * @brief Type alias for character type allocation | |
| * @tparam CharT character type | |
| */ | |
| template <cx_character CharT> | |
| using character_allocator_type = std::allocator<CharT>; | |
| /** | |
| * @brief Type alias for key-value pair type allocation (used mainly by basic_typeface) | |
| * @tparam CharT character type | |
| */ | |
| template <cx_character CharT> | |
| using character_kv_pair_allocator_type = std::allocator<std::pair<const CharT, basic_glyph<CharT>>>; | |
| /** | |
| * @brief Type alias for signed pixel count | |
| */ | |
| using pixel_t = int16_t; | |
| /** | |
| * @brief Type alias for unsigned pixel count | |
| */ | |
| using upixel_t = uint16_t; | |
| }; | |
| #pragma region TEXTURE_RELATED | |
| #define SAE_ENGINE_TEXT_NEW_TEXTURE_TYPE | |
| #include <IndustryPlanet_Package.h> | |
| namespace SAE_ENGINE_TEXT_NAMESPACE | |
| { | |
| struct glyph_texture : public iplanet::pkg::texture | |
| { | |
| using iplanet::pkg::texture::texture; | |
| using iplanet::pkg::texture::operator=; | |
| }; | |
| } | |
| #ifdef SAE_ENGINE_TEXT_NEW_TEXTURE_TYPE | |
| #else | |
| namespace SAE_ENGINE_TEXT_NAMESPACE | |
| { | |
| struct glyph_texture | |
| { | |
| public: | |
| using value_type = uint8_t; | |
| using pointer = value_type*; | |
| using reference = value_type&; | |
| using const_pointer = const value_type*; | |
| using const_reference = const value_type&; | |
| using dimension_type = uint16_t; | |
| using size_type = uint32_t; | |
| using allocator_type = std::allocator<value_type>; | |
| private: | |
| using ContainerT = std::vector<value_type, allocator_type>; | |
| public: | |
| dimension_type width() const noexcept; | |
| dimension_type height() const noexcept; | |
| size_type size() const noexcept; | |
| private: | |
| void _Update_Size(); | |
| public: | |
| void resize(dimension_type _w, dimension_type _h); | |
| void set_width(dimension_type _w); | |
| void set_height(dimension_type _h); | |
| pointer data() noexcept; | |
| const_pointer data() const noexcept; | |
| /** | |
| * @brief Clears the pixel data and sets the texture's width and height to 0 | |
| */ | |
| void clear() noexcept; | |
| /** | |
| * @brief Appends pixel data onto the bottom of the texture | |
| * @param _data Pointer to the pixel data | |
| * @param _count Maximum number of pixel values to append | |
| * @return Number of pixel values appended to the texture | |
| */ | |
| size_type append(const_pointer _data, size_type _count); | |
| glyph_texture() = default; | |
| glyph_texture(dimension_type _width, dimension_type _height); | |
| private: | |
| dimension_type width_ = 0; | |
| dimension_type height_ = 0; | |
| ContainerT pixels_{}; | |
| }; | |
| } | |
| #endif | |
| #pragma endregion TEXTURE_RELATED | |
| #pragma region FREETYPE_INTERFACING | |
| struct FT_LibraryRec_; | |
| typedef struct FT_LibraryRec_* FT_Library; | |
| struct FT_FaceRec_; | |
| typedef struct FT_FaceRec_* FT_Face; | |
| namespace SAE_ENGINE_TEXT_NAMESPACE | |
| { | |
| namespace impl | |
| { | |
| struct FTLibWrapper | |
| { | |
| public: | |
| operator FT_Library () const noexcept; | |
| FTLibWrapper(); | |
| ~FTLibWrapper(); | |
| private: | |
| FT_Library ftlib_ = nullptr; | |
| }; | |
| static inline FTLibWrapper freetype_wrapper_{}; | |
| }; | |
| } | |
| #pragma endregion FREETYPE_INTERFACING | |
| #pragma region GLYPH_IMPLEMENTATION | |
| namespace SAE_ENGINE_TEXT_NAMESPACE | |
| { | |
| namespace impl | |
| { | |
| struct glyph_base | |
| { | |
| public: | |
| struct glyph_bearing | |
| { | |
| pixel_t x = 0; | |
| pixel_t y = 0; | |
| }; | |
| struct glyph_size | |
| { | |
| upixel_t width = 0; | |
| upixel_t height = 0; | |
| }; | |
| struct glyph_advance | |
| { | |
| upixel_t x = 0; | |
| upixel_t y = 0; | |
| }; | |
| void set_size(glyph_size _size) noexcept; | |
| constexpr glyph_size get_size() const noexcept { return this->size_; }; | |
| constexpr auto width() const noexcept { return this->size_.width; }; | |
| constexpr auto height() const noexcept { return this->size_.height; }; | |
| void set_bearing(glyph_bearing _bearing) noexcept; | |
| constexpr glyph_bearing get_bearing() const noexcept { return this->bearing_; }; | |
| constexpr auto bearing_x() const noexcept { return this->bearing_.x; }; | |
| constexpr auto bearing_y() const noexcept { return this->bearing_.y; }; | |
| void set_advance(glyph_advance _advance) noexcept; | |
| constexpr glyph_advance get_advance() const noexcept { return this->advance_; }; | |
| constexpr auto advance_x() const noexcept { return this->advance_.x; }; | |
| constexpr auto advance_y() const noexcept { return this->advance_.y; }; | |
| void set_texcoords(glyph_texcoords _tcoords) noexcept { this->texcoords_ = std::move(_tcoords); }; | |
| constexpr const glyph_texcoords& get_texcoords() const noexcept { return this->texcoords_; }; | |
| constexpr glyph_base() = default; | |
| explicit constexpr glyph_base(glyph_size _s, glyph_bearing _b, glyph_advance _a, glyph_texcoords _tcoords) noexcept : | |
| size_{ _s }, bearing_{ _b }, advance_{ _a }, texcoords_{ _tcoords } | |
| {}; | |
| private: | |
| glyph_texcoords texcoords_{}; | |
| glyph_bearing bearing_{}; | |
| glyph_advance advance_{}; | |
| glyph_size size_{}; | |
| }; | |
| }; | |
| /** | |
| * @brief Holds an RGB color value used to by glyphs | |
| */ | |
| struct glyph_color | |
| { | |
| uint8_t r = 255; | |
| uint8_t g = 255; | |
| uint8_t b = 255; | |
| }; | |
| struct glyph_background_color | |
| { | |
| uint8_t r = 0; | |
| uint8_t g = 0; | |
| uint8_t b = 0; | |
| uint8_t a = 0; | |
| }; | |
| /** | |
| * @brief Aggregate type for any glyph formatting options (such as color) | |
| */ | |
| struct glyph_format | |
| { | |
| glyph_color color{}; | |
| uint8_t font_size = 0; | |
| float_t scale = 1.0f; | |
| glyph_background_color bg_color{}; | |
| }; | |
| /** | |
| * @brief Stores the metrics for a single font character (glyph) | |
| * @tparam CharT character type | |
| */ | |
| template <cx_character CharT> | |
| struct basic_glyph : public impl::glyph_base | |
| { | |
| public: | |
| using character_t = CharT; | |
| void set_char(character_t _char) noexcept { this->glyph_character_ = _char; }; | |
| constexpr character_t get_char() const noexcept { return glyph_character_; }; | |
| constexpr explicit operator character_t() const noexcept { return this->glyph_character_; }; | |
| friend inline constexpr bool operator==(const basic_glyph<CharT>& _lhs, CharT _rhs) noexcept | |
| { | |
| return (_lhs.get_char() == _rhs); | |
| }; | |
| friend inline constexpr bool operator!=(const basic_glyph<CharT>& _lhs, CharT _rhs) noexcept | |
| { | |
| return (_lhs.get_char() != _rhs); | |
| }; | |
| friend inline constexpr bool operator>(const basic_glyph<CharT>& _lhs, const basic_glyph<CharT>& _rhs) noexcept | |
| { | |
| return (_lhs.get_char() > _rhs.get_char()); | |
| }; | |
| friend inline constexpr bool operator<(const basic_glyph<CharT>& _lhs, const basic_glyph<CharT>& _rhs) noexcept | |
| { | |
| return (_lhs.get_char() < _rhs.get_char()); | |
| }; | |
| friend inline constexpr bool operator>=(const basic_glyph<CharT>& _lhs, const basic_glyph<CharT>& _rhs) noexcept | |
| { | |
| return (_lhs.get_char() >= _rhs.get_char()); | |
| }; | |
| friend inline constexpr bool operator<=(const basic_glyph<CharT>& _lhs, const basic_glyph<CharT>& _rhs) noexcept | |
| { | |
| return (_lhs.get_char() <= _rhs.get_char()); | |
| }; | |
| basic_glyph& operator=(character_t _character) noexcept | |
| { | |
| this->glyph_character_ = _character; | |
| return *this; | |
| }; | |
| explicit constexpr basic_glyph() noexcept = default; | |
| explicit constexpr basic_glyph(character_t _character) noexcept : | |
| impl::glyph_base{}, glyph_character_{ _character } | |
| {}; | |
| explicit constexpr basic_glyph(character_t _char, const impl::glyph_base& _gbase) : | |
| impl::glyph_base{ _gbase }, glyph_character_{ _char } | |
| {}; | |
| explicit constexpr basic_glyph(character_t _char, impl::glyph_base&& _gbase) : | |
| impl::glyph_base{ std::move(_gbase) }, glyph_character_{ _char } | |
| {}; | |
| private: | |
| character_t glyph_character_ = 0; | |
| }; | |
| /** | |
| * @brief 8-bit-character basic_glyph type alias | |
| */ | |
| using glyph8_t = basic_glyph<char8_t>; | |
| /** | |
| * @brief 16-bit-character basic_glyph type alias | |
| */ | |
| using glyph16_t = basic_glyph<char16_t>; | |
| /** | |
| * @brief 32-bit-character basic_glyph type alias | |
| */ | |
| using glyph32_t = basic_glyph<char32_t>; | |
| /** | |
| * @brief Stores the metrics for a single font character (glyph) | |
| */ | |
| using glyph = basic_glyph<default_character_t>; | |
| /** | |
| * @brief Holds a glyph and provides formatting support and a handful of helper functions | |
| * @tparam CharT character type | |
| */ | |
| template <cx_character CharT> | |
| struct basic_glyph_instance | |
| { | |
| public: | |
| using character_t = CharT; | |
| using glyph_t = basic_glyph<character_t>; | |
| private: | |
| constexpr float_t _scale() const noexcept { return this->format_.scale; }; | |
| glyph_t& _get_glyph() noexcept { return this->glyph_; }; | |
| constexpr const glyph_t& _get_glyph() const noexcept { return this->glyph_; }; | |
| constexpr upixel_t advance_x(float_t _scale) const noexcept | |
| { | |
| return (upixel_t)((this->_get_glyph().advance_x() >> 6) * _scale); | |
| }; | |
| constexpr upixel_t advance_y(float_t _scale) const noexcept | |
| { | |
| return (upixel_t)((this->_get_glyph().advance_y() >> 6) * _scale); | |
| }; | |
| constexpr pixel_t bearing_x(float_t _scale) const noexcept | |
| { | |
| return (pixel_t)(this->_get_glyph().bearing_x() * _scale); | |
| }; | |
| constexpr pixel_t bearing_x() const noexcept | |
| { | |
| return this->bearing_x(this->_scale()); | |
| }; | |
| constexpr pixel_t bearing_y(float_t _scale) const noexcept | |
| { | |
| return (pixel_t)(this->_get_glyph().bearing_y() * _scale); | |
| }; | |
| constexpr pixel_t bearing_y() const noexcept | |
| { | |
| return this->bearing_y(this->_scale()); | |
| }; | |
| constexpr pixel_t bbox_width(float_t _scale) const noexcept | |
| { | |
| return (pixel_t)(this->_get_glyph().width() * _scale); | |
| }; | |
| constexpr pixel_t bbox_height(float_t _scale) const noexcept | |
| { | |
| return (pixel_t)(this->_get_glyph().height() * _scale); | |
| }; | |
| constexpr pixel_t bbox_left(float_t _scale) const noexcept | |
| { | |
| return this->bearing_x(_scale); | |
| }; | |
| constexpr pixel_t bbox_right(float_t _scale) const noexcept | |
| { | |
| return this->bbox_left(_scale) + this->bbox_width(_scale); | |
| }; | |
| constexpr pixel_t bbox_top(float_t _scale) const noexcept | |
| { | |
| return this->bearing_y(_scale); | |
| }; | |
| constexpr pixel_t bbox_bottom(float_t _scale) const noexcept | |
| { | |
| return bbox_top(_scale) - this->bbox_height(_scale); | |
| }; | |
| constexpr upixel_t width(float_t _scale) const noexcept | |
| { | |
| return (upixel_t)this->advance_x(_scale); | |
| }; | |
| constexpr upixel_t height(float_t _scale) const noexcept | |
| { | |
| return (upixel_t)this->advance_y(_scale); | |
| }; | |
| public: | |
| friend inline constexpr bool operator==(const basic_glyph_instance<character_t>& _lhs, character_t _rhs) noexcept | |
| { | |
| return (_lhs.get_glyph() == _rhs); | |
| }; | |
| friend inline constexpr bool operator!=(const basic_glyph_instance<character_t>& _lhs, character_t _rhs) noexcept | |
| { | |
| return (_lhs.get_glyph() != _rhs); | |
| }; | |
| /** | |
| * @brief Returns the horizontal distance between this glyph and the next glyph's origin in pixels | |
| */ | |
| constexpr upixel_t advance_x() const noexcept | |
| { | |
| return this->advance_x(this->_scale()); | |
| }; | |
| /** | |
| * @brief Returns the vertical distance between this glyph and the next glyph's origin in pixels | |
| */ | |
| constexpr upixel_t advance_y() const noexcept | |
| { | |
| return this->advance_y(this->_scale()); | |
| }; | |
| /** | |
| * @brief Returns distance between the origin and the left side of the glyph's bbox. Add to cursor X to get real position. | |
| */ | |
| constexpr pixel_t bbox_left() const noexcept | |
| { | |
| return this->bbox_left(this->_scale()); | |
| }; | |
| /** | |
| * @brief Returns distance between the origin and the right side of the glyph's bbox. Add to cursor X to get real position. | |
| */ | |
| constexpr pixel_t bbox_right() const noexcept | |
| { | |
| return this->bbox_right(this->_scale()); | |
| }; | |
| /** | |
| * @brief Returns distance between the origin and the top side of the glyph's bbox. Add to cursor Y to get real position. | |
| */ | |
| constexpr pixel_t bbox_top() const noexcept | |
| { | |
| return this->bbox_top(this->_scale()); | |
| }; | |
| /** | |
| * @brief Returns distance between the origin and the bottom side of the glyph's bbox. Add to cursor Y to get real position. | |
| */ | |
| constexpr pixel_t bbox_bottom() const noexcept | |
| { | |
| return this->bbox_bottom(this->_scale()); | |
| }; | |
| /** | |
| * @brief Returns the complete width of the glyph in pixels | |
| */ | |
| constexpr upixel_t width() const noexcept | |
| { | |
| return this->width(this->_scale()); | |
| }; | |
| /** | |
| * @brief Returns the complete height of the glyph in pixels | |
| */ | |
| constexpr upixel_t height() const noexcept | |
| { | |
| return this->height(this->_scale()); | |
| }; | |
| /** | |
| * @brief Sets the glyph formatting to the format provided | |
| */ | |
| void set_format(glyph_format _fmt) noexcept | |
| { | |
| this->format_ = std::move(_fmt); | |
| }; | |
| /** | |
| * @brief Returns non-const reference to the glyph's formatting | |
| */ | |
| glyph_format& get_format() noexcept | |
| { | |
| return this->format_; | |
| }; | |
| /** | |
| * @brief Returns const reference to the glyph's formatting | |
| */ | |
| constexpr const glyph_format& get_format() const noexcept | |
| { | |
| return this->format_; | |
| }; | |
| /** | |
| * @brief Returns the RGB color value assigned to this glyph | |
| */ | |
| constexpr glyph_color color() const noexcept | |
| { | |
| return this->get_format().color; | |
| }; | |
| /** | |
| * @brief Sets the glyph used by the glyph instance, copy overload | |
| */ | |
| void set_glyph(const glyph_t& _g) noexcept | |
| { | |
| this->glyph_ = _g; | |
| }; | |
| /** | |
| * @brief Sets the glyph used by the glyph instance, move overload | |
| */ | |
| void set_glyph(glyph_t&& _g) noexcept | |
| { | |
| this->glyph_ = std::move(_g); | |
| }; | |
| /** | |
| * @brief Returns a non-const reference to the glyph instance's internal glyph | |
| */ | |
| glyph_t& get_glyph() noexcept | |
| { | |
| return this->_get_glyph(); | |
| }; | |
| /** | |
| * @brief Returns a const reference to the glyph instance's internal glyph | |
| */ | |
| constexpr const glyph_t& get_glyph() const noexcept | |
| { | |
| return this->_get_glyph(); | |
| }; | |
| constexpr explicit basic_glyph_instance(const glyph_t& _g, glyph_format _fmt) noexcept(noexcept(glyph_t(glyph_t{}))) : | |
| glyph_{ _g }, format_{ _fmt } | |
| {}; | |
| constexpr explicit basic_glyph_instance(glyph_t&& _g, glyph_format _fmt) noexcept : | |
| glyph_{ std::move(_g) }, format_{ _fmt } | |
| {}; | |
| constexpr explicit basic_glyph_instance(const glyph_t& _g) noexcept(noexcept(glyph_t(glyph_t{}))) : | |
| basic_glyph_instance{ _g, {} } | |
| {}; | |
| constexpr explicit basic_glyph_instance(glyph_t&& _g) noexcept : | |
| basic_glyph_instance{ std::move(_g), {} } | |
| {}; | |
| basic_glyph_instance& operator=(const glyph_t& _g) noexcept(noexcept(glyph_t(glyph_t{}))) | |
| { | |
| this->glyph_ = _g; | |
| return *this; | |
| }; | |
| basic_glyph_instance& operator=(glyph_t&& _g) noexcept | |
| { | |
| this->glyph_ = std::move(_g); | |
| return *this; | |
| }; | |
| constexpr basic_glyph_instance() noexcept = default; | |
| constexpr basic_glyph_instance(const basic_glyph_instance& other) noexcept = default; | |
| basic_glyph_instance& operator=(const basic_glyph_instance& other) noexcept = default; | |
| constexpr basic_glyph_instance(basic_glyph_instance&& other) noexcept = default; | |
| basic_glyph_instance& operator=(basic_glyph_instance&& other) noexcept = default; | |
| private: | |
| glyph_format format_{}; | |
| glyph_t glyph_{}; | |
| }; | |
| /** | |
| * @brief 8-bit-character basic_glyph_instance type alias | |
| */ | |
| using glyph_instance8_t = basic_glyph_instance<char8_t>; | |
| /** | |
| * @brief 16-bit-character basic_glyph_instance type alias | |
| */ | |
| using glyph_instance16_t = basic_glyph_instance<char16_t>; | |
| /** | |
| * @brief 32-bit-character basic_glyph_instance type alias | |
| */ | |
| using glyph_instance32_t = basic_glyph_instance<char32_t>; | |
| /** | |
| * @brief Holds a glyph and provides formatting support and a handful of helper functions | |
| */ | |
| using glyph_instance = basic_glyph_instance<default_character_t>; | |
| } | |
| #pragma endregion GLYPH_IMPLEMENTATION | |
| #pragma region FONT_LOADING | |
| namespace SAE_ENGINE_TEXT_NAMESPACE | |
| { | |
| namespace impl | |
| { | |
| struct FontFaceLoader | |
| { | |
| private: | |
| FT_Face& _get_face() noexcept; | |
| const FT_Face& _get_face() const noexcept; | |
| std::pair<impl::glyph_base, glyph_texture> _load_font_glyph(uint32_t _charCode); | |
| void _set_pixel_sizes(size_t _width, size_t _height); | |
| FT_Face _set_font_face(std::filesystem::path _fontPath); | |
| void _free_face(FT_Face& _face); | |
| public: | |
| template <cx_character CharT> | |
| std::pair<basic_glyph<CharT>, glyph_texture> load_glyph(CharT _charCode) | |
| { | |
| auto _gotGlyph = this->_load_font_glyph((uint32_t)_charCode); | |
| return std::pair<basic_glyph<CharT>, glyph_texture> | |
| { | |
| basic_glyph<CharT>{ _charCode, std::move(_gotGlyph.first) }, | |
| std::move(_gotGlyph.second) | |
| }; | |
| }; | |
| std::pair<size_t, size_t> max_glyph_image_size() const; | |
| bool is_open() const noexcept; | |
| bool is_closed() const noexcept; | |
| bool open(); | |
| bool close(); | |
| void set_font_path(const std::filesystem::path& _fpath); | |
| void set_font_size(size_t _pxwidth, size_t _pxheight); | |
| size_t px_width() const noexcept; | |
| size_t px_height() const noexcept; | |
| int16_t linespace() const; | |
| int16_t max_advance() const; | |
| int16_t face_height() const; | |
| int16_t ascender() const; | |
| int16_t descender() const; | |
| explicit FontFaceLoader() = default; | |
| explicit FontFaceLoader(std::filesystem::path _fontPath); | |
| explicit FontFaceLoader(std::filesystem::path _fontPath, size_t _pxwidth, size_t _pxheight); | |
| ~FontFaceLoader(); | |
| private: | |
| std::filesystem::path font_path_{}; | |
| bool is_open_ = false; | |
| FT_Face face_ = nullptr; | |
| size_t px_width_ = 0; | |
| size_t px_height_ = 0; | |
| }; | |
| }; | |
| using fontface_loader_t = impl::FontFaceLoader; | |
| } | |
| #pragma endregion FONT_LOADING | |
| #pragma region FONT_AND TYPEFACE | |
| namespace SAE_ENGINE_TEXT_NAMESPACE | |
| { | |
| /** | |
| * @brief Container type that stores a single font typeface alonsgide various font metrics such as linespacing | |
| * @tparam CharT character type | |
| */ | |
| template <cx_character CharT> | |
| struct basic_typeface | |
| { | |
| public: | |
| using character_t = CharT; | |
| using glyph_t = basic_glyph<character_t>; | |
| using value_type = glyph_t; | |
| using pointer = typename value_type*; | |
| using reference = typename value_type&; | |
| using const_pointer = const typename value_type*; | |
| using const_reference = const typename value_type&; | |
| using allocator_type = character_kv_pair_allocator_type<character_t>; | |
| private: | |
| using key_type = character_t; | |
| using ContainerT = std::map<key_type, glyph_t, std::less<key_type>, allocator_type>; | |
| public: | |
| using iterator = typename ContainerT::iterator; | |
| using const_iterator = typename ContainerT::const_iterator; | |
| using reverse_iterator = typename ContainerT::reverse_iterator; | |
| using const_reverse_iterator = typename ContainerT::const_reverse_iterator; | |
| iterator begin() noexcept { return this->glyphs_.begin(); }; | |
| const_iterator begin() const noexcept { return this->glyphs_.cbegin(); }; | |
| const_iterator cbegin() const noexcept { return this->glyphs_.cbegin(); }; | |
| iterator end() noexcept { return this->glyphs_.end(); }; | |
| const_iterator end() const noexcept { return this->glyphs_.cend(); }; | |
| const_iterator cend() const noexcept { return this->glyphs_.cend(); }; | |
| reverse_iterator rbegin() noexcept { return this->glyphs_.rbegin(); }; | |
| const_reverse_iterator rbegin() const noexcept { return this->glyphs_.crbegin(); }; | |
| const_reverse_iterator crbegin() const noexcept { return this->glyphs_.crbegin(); }; | |
| reverse_iterator rend() noexcept { return this->glyphs_.rend(); }; | |
| const_reverse_iterator rend() const noexcept { return this->glyphs_.crend(); }; | |
| const_reverse_iterator crend() const noexcept { return this->glyphs_.crend(); }; | |
| size_t size() const noexcept { return this->glyphs_.size(); }; | |
| void push(const glyph_t& _glyph) | |
| { | |
| auto _glyphCharacter = _glyph.get_char(); | |
| this->glyphs_.insert({ this->size(), _glyph }); | |
| }; | |
| void push(glyph_t&& _glyph) | |
| { | |
| auto _glyphCharacter = _glyph.get_char(); | |
| this->glyphs_.insert({ this->size(), std::move(_glyph) }); | |
| }; | |
| void clear() noexcept { this->glyphs_.clear(); }; | |
| reference at(key_type _i) { return this->glyphs_.at(_i); }; | |
| const_reference at(key_type _i) const { return this->glyphs_.at(_i); }; | |
| reference operator[](key_type _i) { return this->at(_i); }; | |
| const_reference operator[](key_type _i) const { return this->at(_i); }; | |
| bool contains(key_type _i) const noexcept { return this->glyphs_.contains(_i); }; | |
| int16_t max_advance() const noexcept { return this->max_advance_; }; | |
| void set_max_advance(int16_t _px) noexcept { this->max_advance_ = _px; }; | |
| int16_t height() const noexcept { return this->height_; } | |
| void set_height(int16_t _px) noexcept { this->height_ = _px; }; | |
| int16_t linespace() const noexcept { return this->linespace_; }; | |
| void set_linespace(int16_t _px) noexcept { this->linespace_ = _px; }; | |
| int16_t ascender() const noexcept { return this->ascender_; }; | |
| void set_ascender(int16_t _px) noexcept { this->ascender_ = _px; }; | |
| int16_t descender() const noexcept { return this->descender_; }; | |
| void set_descender(int16_t _px) noexcept { this->descender_ = _px; }; | |
| basic_typeface() = default; | |
| private: | |
| int16_t max_advance_ = 0; | |
| int16_t height_ = 0; | |
| int16_t linespace_ = 0; | |
| int16_t ascender_ = 0; | |
| int16_t descender_ = 0; | |
| ContainerT glyphs_{}; | |
| }; | |
| /** | |
| * @brief 8-bit-character basic_typeface type alias | |
| */ | |
| using typeface8_t = basic_typeface<char8_t>; | |
| /** | |
| * @brief 16-bit-character basic_typeface type alias | |
| */ | |
| using typeface16_t = basic_typeface<char16_t>; | |
| /** | |
| * @brief 32-bit-character basic_typeface type alias | |
| */ | |
| using typeface32_t = basic_typeface<char32_t>; | |
| /** | |
| * @brief Container type that stores a single font typeface alonsgide various font metrics such as linespacing | |
| */ | |
| using typeface = basic_typeface<default_character_t>; | |
| /** | |
| * @brief Manages a set of typefaces that follow a similar style - AKA a font. | |
| * @tparam CharT character type | |
| */ | |
| template <cx_character CharT> | |
| struct basic_font | |
| { | |
| public: | |
| using character_t = CharT; | |
| using glyph_t = basic_glyph<character_t>; | |
| using typeface_t = basic_typeface<character_t>; | |
| private: | |
| uint16_t glyph_count_ = 0; | |
| std::vector<std::vector<typeface_t>> typefaces_{}; | |
| public: | |
| using character_t = CharT; | |
| using glyph_t = basic_glyph<character_t>; | |
| using typeface_t = basic_typeface<character_t>; | |
| void clear() noexcept | |
| { | |
| this->typefaces_.clear(); | |
| }; | |
| const glyph_t& get_glyph(character_t _glyphCode, uint8_t _size, uint8_t _style) const | |
| { | |
| assert(_style < this->typefaces_.size()); | |
| return this->typefaces_[_style][_size][_glyphCode]; | |
| }; | |
| const glyph_t& get_glyph(character_t _glyphCode, uint8_t _size) const | |
| { | |
| return this->get_glyph(_glyphCode, _size, 0); | |
| }; | |
| const glyph_t& get_glyph(character_t _glyphCode) const | |
| { | |
| return this->get_glyph(_glyphCode, 0, 0); | |
| }; | |
| /** | |
| * @brief Returns the total number of glyphs per typeface in the font | |
| */ | |
| uint16_t glyph_count() const | |
| { | |
| return this->glyph_count_; | |
| }; | |
| const typeface_t& get_typeface(uint8_t _style, uint8_t _size) const | |
| { | |
| assert(_style < this->typefaces_.size()); | |
| return this->typefaces_.at(_style).at(_size); | |
| }; | |
| const typeface_t& get_typeface(uint8_t _style) const | |
| { | |
| assert(_style < this->typefaces_.size()); | |
| return this->typefaces_.at(_style).at(0); | |
| }; | |
| private: | |
| bool load(const std::filesystem::path& _typefacePath, typeface_t& _tface, uint16_t _glyphHeight, fontface_loader_t _loader) | |
| { | |
| if (_loader.is_open()) | |
| if (!_loader.close()) | |
| abort(); | |
| _loader.set_font_path(_typefacePath); | |
| _loader.set_font_size(0, (size_t)_glyphHeight); | |
| if (!_loader.open()) | |
| return false; | |
| auto _maxSize = _loader.max_glyph_image_size(); | |
| _tface.set_height(_loader.face_height() >> 6); | |
| _tface.set_max_advance(_loader.max_advance() >> 6); | |
| _tface.set_ascender(_loader.ascender() >> 6); | |
| _tface.set_descender(_loader.descender() >> 6); | |
| _tface.set_linespace(_loader.linespace() >> 6); | |
| for (character_t c = 0; c < this->glyph_count(); ++c) | |
| { | |
| auto _gPair = _loader.load_glyph<character_t>(c); | |
| auto _tcoords = this->get_texture_sheet().append_to_sheet(_gPair.second); | |
| _gPair.first.set_texcoords(_tcoords); | |
| _tface.push(_gPair.first); | |
| }; | |
| assert(this->tex_.subtex_width() >= _maxSize.first); | |
| assert(this->tex_.subtex_height() >= _maxSize.second); | |
| if (!_loader.close()) | |
| return false; | |
| return true; | |
| }; | |
| public: | |
| constexpr static inline int8_t LOAD_ERROR = -1; | |
| /** | |
| * @brief Loads a type face into the font | |
| * @param _fpath Path to the type face (.ttf or .otf) | |
| * @param _glyphCount Number of glyphs in the font face | |
| * @return The style index of the type face or LOAD_ERROR on failure | |
| */ | |
| int8_t load_typeface(const std::filesystem::path& _fpath, character_t _glyphCount) | |
| { | |
| int8_t _style = (int8_t)this->typefaces_.size(); | |
| if (_style < LOAD_ERROR) | |
| return LOAD_ERROR; | |
| this->glyph_count_ = _glyphCount; | |
| const std::array<uint8_t, 4> _loadSizes{ 12, 18, 24, 32 }; | |
| const auto _maxSize = *std::max_element(_loadSizes.begin(), _loadSizes.end()); | |
| this->tex_ = texture_sheet{ texture::TEXTURE_ENCODING::R_8, (size_t)_maxSize, (size_t)_maxSize }; | |
| this->typefaces_.push_back({}); | |
| for (auto& s : _loadSizes) | |
| { | |
| fontface_loader_t _fload{}; | |
| typeface_t _tface{}; | |
| if (this->load(_fpath, _tface, (uint16_t)s, _fload)) | |
| { | |
| this->typefaces_.back().push_back(std::move(_tface)); | |
| } | |
| else | |
| { | |
| this->typefaces_.back().pop_back(); | |
| return LOAD_ERROR; | |
| }; | |
| }; | |
| return _style; | |
| }; | |
| /** | |
| * @brief Loads a type face into the font | |
| * @param _fpath Path to the type face (.ttf or .otf) | |
| * @return The style index of the type face or LOAD_ERROR on failure | |
| */ | |
| int8_t load_typeface(const std::filesystem::path& _fpath) | |
| { | |
| return this->load_typeface(_fpath, std::numeric_limits<character_t>::max()); | |
| }; | |
| texture_sheet& get_texture_sheet() noexcept { return this->tex_; }; | |
| const texture_sheet& get_texture_sheet() const noexcept { return this->tex_; }; | |
| basic_font() = default; | |
| private: | |
| texture_sheet tex_{}; | |
| std::vector<uint8_t> face_sizes_{}; | |
| }; | |
| /** | |
| * @brief 8-bit-character basic_font type alias | |
| */ | |
| using font8_t = basic_font<char8_t>; | |
| /** | |
| * @brief 16-bit-character basic_font type alias | |
| */ | |
| using font16_t = basic_font<char16_t>; | |
| /** | |
| * @brief 32-bit-character basic_font type alias | |
| */ | |
| using font32_t = basic_font<char32_t>; | |
| /** | |
| * @brief Manages a set of typefaces that follow a similar style - AKA a font. | |
| */ | |
| using font = basic_font<default_character_t>; | |
| /** | |
| * @brief Stores a string of glyphs and provides an std::string-like interface | |
| * @tparam CharT character type | |
| */ | |
| template <cx_character CharT> | |
| struct basic_glyph_string | |
| { | |
| public: | |
| using character_t = char; | |
| using glyph_t = basic_glyph<character_t>; | |
| using font_t = basic_font<character_t>; | |
| using iglyph_t = basic_glyph_instance<character_t>; | |
| using size_type = size_t; | |
| private: | |
| font_t* _get_font() const noexcept { return this->font_; }; | |
| public: | |
| using ContainerT = std::vector<iglyph_t>; | |
| const font_t* get_font() const noexcept { return this->_get_font(); }; | |
| public: | |
| using iterator = typename ContainerT::iterator; | |
| using const_iterator = typename ContainerT::const_iterator; | |
| iterator begin() noexcept { return this->str_.begin(); }; | |
| const_iterator begin() const noexcept { return this->str_.cbegin(); }; | |
| const_iterator cbegin() const noexcept { return this->str_.cbegin(); }; | |
| iterator end() noexcept { return this->str_.end(); }; | |
| const_iterator end() const noexcept { return this->str_.cend(); }; | |
| const_iterator cend() const noexcept { return this->str_.cend(); }; | |
| private: | |
| float_t scale() const noexcept { return this->default_formatting_.scale; }; | |
| public: | |
| void clear() noexcept | |
| { | |
| this->str_.clear(); | |
| }; | |
| size_type size() const noexcept | |
| { | |
| return this->str_.size(); | |
| }; | |
| iglyph_t& at(size_type _i) { return this->str_.at(_i); }; | |
| const iglyph_t& at(size_type _i) const { return this->str_.at(_i); }; | |
| iglyph_t& operator[](size_type _i) { return this->at(_i); }; | |
| const iglyph_t& operator[](size_type _i) const { return this->at(_i); }; | |
| std::string string() const | |
| { | |
| std::string _out{}; | |
| _out.reserve(this->size()); | |
| for (const auto& c : this->str_) | |
| { | |
| _out += c.get_glyph().get_char(); | |
| }; | |
| return _out; | |
| }; | |
| private: | |
| size_type _find(character_t _c, size_type _pos) const | |
| { | |
| for (; _pos < this->size(); ++_pos) | |
| { | |
| if (this->at(_pos) == _c) | |
| break; | |
| }; | |
| return _pos; | |
| }; | |
| template <typename _CharTraitsT, typename _AllocT> | |
| size_type _find(const std::basic_string<character_t, _CharTraitsT, _AllocT>& _str, size_type _pos) const | |
| { | |
| auto _strIt = _str.begin(); | |
| auto _strEnd = _str.end(); | |
| for (; _pos < this->size(); ++_pos) | |
| { | |
| if (this->at(_pos) == *_strIt) | |
| { | |
| ++_strIt; | |
| } | |
| else | |
| { | |
| _strIt = _strEnd; | |
| }; | |
| if (_strIt == _str.end()) | |
| return _pos - _str.size(); | |
| }; | |
| return _pos; | |
| }; | |
| protected: | |
| void set_font(font_t* _font) | |
| { | |
| this->clear(); | |
| this->font_ = _font; | |
| }; | |
| public: | |
| iterator find(character_t _c, iterator _pos) | |
| { | |
| return this->begin() + this->_find(_c, _pos - this->begin()); | |
| }; | |
| const_iterator find(character_t _c, const_iterator _pos) const | |
| { | |
| return this->cbegin() + this->_find(_c, _pos - this->cbegin()); | |
| }; | |
| iterator find(character_t _c) | |
| { | |
| return this->find(_c, this->begin()); | |
| }; | |
| const_iterator find(character_t _c) const | |
| { | |
| return this->find(_c, this->cbegin()); | |
| }; | |
| template <typename _CharTraitsT, typename _AllocT> | |
| iterator find(const std::basic_string<character_t, _CharTraitsT, _AllocT>& _str, iterator _pos) | |
| { | |
| return this->begin() + this->_find(_str, _pos - this->begin()); | |
| }; | |
| template <typename _CharTraitsT, typename _AllocT> | |
| const_iterator find(const std::basic_string<character_t, _CharTraitsT, _AllocT>& _str, const_iterator _pos) const | |
| { | |
| return this->cbegin() + this->_find(_str, _pos - this->cbegin()); | |
| }; | |
| template <typename _CharTraitsT, typename _AllocT> | |
| iterator find(const std::basic_string<character_t, _CharTraitsT, _AllocT>& _str) | |
| { | |
| return this->find(_str, this->begin()); | |
| }; | |
| template <typename _CharTraitsT, typename _AllocT> | |
| const_iterator find(const std::basic_string<character_t, _CharTraitsT, _AllocT>& _str) const | |
| { | |
| return this->find(_str, this->cbegin()); | |
| }; | |
| /** | |
| * @brief Sets the format of the glyphs within the specified range to the provided glyph formatting | |
| * @param _begin Beginning of glyph range | |
| * @param _end End of glyph range | |
| * @param _fmt Format to use | |
| * @return Iterator to final glyph that was formatted | |
| */ | |
| iterator format(iterator _begin, iterator _end, glyph_format _fmt) | |
| { | |
| glyph_texcoords _gtexcoords{}; | |
| for (; _begin != _end; ++_begin) | |
| { | |
| _begin->get_glyph() = this->get_font()->get_glyph(_begin->get_glyph().get_char(), _fmt.font_size); | |
| _begin->set_format(_fmt); | |
| }; | |
| return _begin; | |
| }; | |
| /** | |
| * @brief Sets the format of the glyph at the provided iterator to the provided glyph formatting | |
| * @param _it Beginning of glyph range | |
| * @return Iterator to the glyph that was formatted | |
| */ | |
| iterator format(iterator _it, const glyph_format& _fmt) | |
| { | |
| return this->format(_it, _it + 1, _fmt); | |
| }; | |
| iterator insert(iterator _at, character_t _char, const glyph_format& _fmt) | |
| { | |
| iterator _out{}; | |
| _out = this->str_.insert(_at, iglyph_t{ this->_get_font()->get_glyph(((uint16_t)_char), _fmt.font_size), _fmt }); | |
| this->format(_out, _fmt); | |
| return _out; | |
| }; | |
| iterator insert(iterator _at, character_t _char) | |
| { | |
| return this->insert(_at, _char, this->default_formatting_); | |
| }; | |
| template <typename _IterT> | |
| iterator insert(iterator _at, _IterT _begin, _IterT _end, const glyph_format& _fmt) | |
| { | |
| auto _atcopy = _at; | |
| for (; _begin != _end; ++_begin) | |
| { | |
| _at = this->insert(_at, *_begin, _fmt); | |
| ++_at; | |
| }; | |
| return _atcopy; | |
| }; | |
| template <typename SrcCharIterT> | |
| iterator insert(iterator _at, SrcCharIterT _begin, SrcCharIterT _end) | |
| { | |
| return this->insert(_at, _begin, _end, this->default_formatting_); | |
| }; | |
| void push_back(character_t _char, size_type _count, const glyph_format& _fmt) | |
| { | |
| for (size_type i = 0; i < _count; ++i) | |
| { | |
| this->insert(this->end(), _char, _fmt); | |
| }; | |
| }; | |
| void push_back(character_t _char, size_type _count) | |
| { | |
| this->push_back(_char, _count, this->default_formatting_); | |
| }; | |
| void push_back(character_t _char, glyph_format _fmt) | |
| { | |
| this->push_back(_char, 1, _fmt); | |
| }; | |
| void push_back(character_t _char) | |
| { | |
| this->push_back(_char, 1); | |
| }; | |
| template <typename CharTraits, typename Alloc> | |
| void append(const std::basic_string<character_t, CharTraits, Alloc>& _str, glyph_format _fmt) | |
| { | |
| for (auto& c : _str) | |
| { | |
| this->push_back(c, _fmt); | |
| }; | |
| }; | |
| template <typename CharTraits, typename Alloc> | |
| void append(const std::basic_string<character_t, CharTraits, Alloc>& _str) | |
| { | |
| this->append(_str, this->default_formatting_); | |
| }; | |
| void append(const character_t* _cstr, size_type _len, glyph_format _fmt) | |
| { | |
| for (const character_t* ptr = _cstr; (ptr - _cstr) != _len; ++ptr) | |
| { | |
| this->push_back(*ptr, _fmt); | |
| }; | |
| }; | |
| void append(const character_t* _cstr, size_type _len) | |
| { | |
| this->append(_cstr, this->default_formatting_); | |
| }; | |
| void append(const character_t* _cstr, glyph_format _fmt) | |
| { | |
| this->append(_cstr, std::strlen((const char*)_cstr), _fmt); | |
| }; | |
| void append(const character_t* _cstr) | |
| { | |
| this->append(_cstr, std::strlen((const char*)_cstr)); | |
| }; | |
| template <typename CharTraits, typename Alloc> | |
| void assign(const std::basic_string<character_t, CharTraits, Alloc>& _str, glyph_format _fmt) | |
| { | |
| this->str_.clear(); | |
| this->str_.reserve(_str.size()); | |
| for (auto& c : _str) | |
| { | |
| this->push_back(c, _fmt); | |
| }; | |
| }; | |
| template <typename CharTraits, typename Alloc> | |
| void assign(const std::basic_string<character_t, CharTraits, Alloc>& _str) | |
| { | |
| this->assign(_str, this->default_formatting_); | |
| }; | |
| void assign(const character_t* _cstr, size_type _len, glyph_format _fmt) | |
| { | |
| this->clear(); | |
| for (const character_t* ptr = _cstr; (ptr - _cstr) != _len; ++ptr) | |
| { | |
| this->push_back(*ptr, _fmt); | |
| }; | |
| }; | |
| void assign(const character_t* _cstr, size_type _len) | |
| { | |
| this->assign(_cstr, _len, this->default_formatting_); | |
| }; | |
| void assign(const character_t* _cstr, glyph_format _fmt) | |
| { | |
| this->assign(_cstr, std::strlen(_cstr), _fmt); | |
| }; | |
| void assign(const typename character_t* _cstr) | |
| { | |
| this->assign(_cstr, std::strlen((const char*)_cstr)); | |
| }; | |
| iterator erase(const_iterator _at) | |
| { | |
| return this->str_.erase(_at); | |
| }; | |
| iterator erase(const_iterator _begin, const_iterator _end) | |
| { | |
| return this->str_.erase(_begin, _end); | |
| }; | |
| void pop_back(size_t _count) | |
| { | |
| if(this->size() >= _count) | |
| this->erase(this->end() - _count, this->end()); | |
| }; | |
| void pop_back() | |
| { | |
| this->pop_back(1); | |
| }; | |
| std::string substr(const_iterator _begin, const_iterator _end) const | |
| { | |
| std::string _out{}; | |
| _out.reserve(_end - _begin); | |
| for (; _begin != _end; ++_begin) | |
| { | |
| _out.push_back(_begin->get_glyph().get_char()); | |
| }; | |
| return _out; | |
| }; | |
| std::string substr(size_t _offset, size_t _count) const | |
| { | |
| auto _at = this->begin() + _offset; | |
| return this->substr(_at, _at + _count); | |
| }; | |
| friend inline std::ostream& operator<<(std::ostream& _ostr, const basic_glyph_string<CharT>& _txt) | |
| { | |
| return _ostr << _txt.string(); | |
| }; | |
| friend inline std::istream& operator>>(std::istream& _istr, basic_glyph_string<CharT>& _txt) | |
| { | |
| std::basic_string<character_t> _str{}; | |
| _istr >> _str; | |
| _txt.assign(_str); | |
| return _istr; | |
| }; | |
| /** | |
| * @brief Sets the active formatting value. Any operations that can take formatting will use the active formatting value | |
| * instead if said operation is not provided a format. For example, calling format_all() without provided a format | |
| */ | |
| void set_formatting(glyph_format _fmt) | |
| { | |
| this->default_formatting_ = _fmt; | |
| }; | |
| /** | |
| * @brief Returns a non-const reference to the active glyph formatting | |
| */ | |
| glyph_format& get_active_formatting() noexcept | |
| { | |
| return this->default_formatting_; | |
| }; | |
| /** | |
| * @brief Returns a const reference to the active glyph formatting | |
| */ | |
| const glyph_format& get_active_formatting() const noexcept | |
| { | |
| return this->default_formatting_; | |
| }; | |
| /** | |
| * @brief Sets all glyph formattnig to the provided formt | |
| */ | |
| void format_all(glyph_format _fmt) | |
| { | |
| this->format(this->begin(), this->end(), _fmt); | |
| }; | |
| /** | |
| * @brief Sets all glyph formatting to the currently set formatting (set using set_formatting()) | |
| */ | |
| void format_all() | |
| { | |
| this->format_all(this->default_formatting_); | |
| }; | |
| basic_glyph_string& operator=(const std::string& _str) | |
| { | |
| this->assign(_str); | |
| return *this; | |
| }; | |
| explicit basic_glyph_string(font_t* _font) : | |
| font_{ _font } | |
| {}; | |
| template <typename CharTraits, typename Alloc> | |
| explicit basic_glyph_string(font_t* _font, const std::basic_string<character_t, CharTraits, Alloc>& _str) : | |
| font_{ _font } | |
| { | |
| this->assign(_str); | |
| }; | |
| template <typename CharTraits, typename Alloc> | |
| explicit basic_glyph_string(font_t* _font, const std::basic_string<character_t, CharTraits, Alloc>& _str, glyph_format _fmt) : | |
| default_formatting_{ _fmt }, font_ { _font } | |
| { | |
| this->assign(_str); | |
| }; | |
| explicit basic_glyph_string(font_t* _font, const character_t* _cstr) : | |
| font_{ _font } | |
| { | |
| this->assign(_cstr); | |
| }; | |
| explicit basic_glyph_string(font_t* _font, const character_t* _cstr, glyph_format _fmt) : | |
| default_formatting_{ _fmt }, font_{ _font } | |
| { | |
| this->assign(_cstr); | |
| }; | |
| explicit basic_glyph_string(font_t* _font, const character_t* _cstr, size_t _len) : | |
| font_{ _font } | |
| { | |
| this->assign(_cstr, _len); | |
| }; | |
| explicit basic_glyph_string(font_t* _font, const character_t* _cstr, size_t _len, glyph_format _fmt) : | |
| default_formatting_{ _fmt }, font_{ _font } | |
| { | |
| this->assign(_cstr, _len); | |
| }; | |
| basic_glyph_string(const basic_glyph_string& other) = default; | |
| basic_glyph_string& operator=(const basic_glyph_string& other) = default; | |
| basic_glyph_string(basic_glyph_string&& other) noexcept = default; | |
| basic_glyph_string& operator=(basic_glyph_string && other) noexcept = default; | |
| private: | |
| font_t* font_ = nullptr; | |
| ContainerT str_{}; | |
| glyph_format default_formatting_{}; | |
| }; | |
| /** | |
| * @brief 8-bit-character basic_glyph_string type alias | |
| */ | |
| using glyph_string8_t = basic_glyph_string<char8_t>; | |
| /** | |
| * @brief 16-bit-character basic_glyph_string type alias | |
| */ | |
| using glyph_string16_t = basic_glyph_string<char16_t>; | |
| /** | |
| * @brief 32-bit-character basic_glyph_string type alias | |
| */ | |
| using glyph_string32_t = basic_glyph_string<char32_t>; | |
| /** | |
| * @brief Stores a string of glyphs and provides an std::string-like interface | |
| */ | |
| using glyph_string = basic_glyph_string<default_character_t>; | |
| template <cx_character CharT> | |
| struct font_list | |
| { | |
| public: | |
| using character_type = CharT; | |
| using font_type = basic_font<character_type>; | |
| private: | |
| using ContainerT = std::unordered_map<std::string, std::unique_ptr<font_type>>; | |
| public: | |
| using iterator = typename ContainerT::iterator; | |
| using const_iterator = typename ContainerT::const_iterator; | |
| iterator begin() noexcept { return this->fonts_.begin(); }; | |
| const_iterator begin() const noexcept { return this->fonts_.cbegin(); }; | |
| const_iterator cbegin() const noexcept { return this->fonts_.cbegin(); }; | |
| iterator end() noexcept { return this->fonts_.end(); }; | |
| const_iterator end() const noexcept { return this->fonts_.cend(); }; | |
| const_iterator cend() const noexcept { return this->fonts_.cend(); }; | |
| void append_font(const std::string& _name, std::unique_ptr<font_type> _font) | |
| { | |
| this->fonts_.insert({ _name, std::move(_font) }); | |
| }; | |
| bool contains(const std::string& _name) const | |
| { | |
| return fonts_.contains(_name); | |
| }; | |
| void erase(const std::string& _name) | |
| { | |
| this->fonts_.erase(_name); | |
| }; | |
| void clear() noexcept | |
| { | |
| this->fonts_.clear(); | |
| }; | |
| font_type* at(const std::string& _name) | |
| { | |
| return this->fonts_.at(_name).get(); | |
| }; | |
| const font_type* at(const std::string& _name) const | |
| { | |
| return this->fonts_.at(_name).get(); | |
| }; | |
| font_list() = default; | |
| private: | |
| ContainerT fonts_{}; | |
| }; | |
| }; | |
| #pragma endregion FONT_AND TYPEFACE |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment