#include #include namespace psemek::ui { monospace_font::monospace_font(character_range range, std::string_view name, geom::vector size, gfx::texture_2d atlas, std::vector> texcoords) : range_{range} , name_{name} , size_{size} , atlas_{std::move(atlas)} , texcoords_{std::move(texcoords)} { if (range_.end - range_.begin != texcoords_.size()) throw std::runtime_error("Wrong number of texture coordinates"); if (!supports_character('?')) throw std::runtime_error("Monospace font must support '?' character"); } static geom::vector advance_dir(shape_options::direction_t direction) { switch (direction) { case shape_options::left_to_right: return {1.f, 0.f}; case shape_options::right_to_left: return {-1.f, 0.f}; case shape_options::top_to_bottom: return {0.f, 1.f}; case shape_options::bottom_to_top: return {0.f, -1.f}; } return {1.f, 0.f}; } bool monospace_font::supports_character(char32_t c) const { return std::isspace(c) || (c >= range_.begin && c < range_.end); } std::vector monospace_font::shape(std::string_view str, shape_options const & options) const { return shape_impl(util::utf8_range(str), options); } std::vector monospace_font::shape(std::u32string_view str, shape_options const & options) const { return shape_impl(str, options); } template std::vector monospace_font::shape_impl(String const & str, shape_options const & options) const { char32_t const unknown = supports_character(options.unknown_character) ? options.unknown_character : '?'; geom::vector const size = geom::cast(this->size()) * options.scale; geom::vector const advance = geom::pointwise_mult(advance_dir(options.direction), size); std::vector result; geom::vector pos{0.f, 0.f}; for (char32_t c : str) { glyph g; if (std::isspace(c)) { g.character = c; g.position = {{{pos[0], pos[0]}, {pos[1], pos[1]}}}; } else { g.character = supports_character(c) ? c : unknown; g.position = {{{pos[0], pos[0] + size[0]}, {pos[1], pos[1] + size[1]}}}; } result.push_back(g); pos += advance; } return result; } std::optional> monospace_font::texcoords(char32_t c) const { if (!supports_character(c)) return std::nullopt; if (std::isspace(c)) return texcoords_[' ' - range_.begin]; return texcoords_[c - range_.begin]; } }