/
d.vision
/
division_engine_cpp
Обзор
Документация
Войти
/
d.vision
/
division_engine_cpp
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/core/font_texture.cpp
136 строк
4 KB
Den163
Removed mac includes
05 дек 2024, 21:30
05 дек 2024, 21:30
f5520fb
Код
Авторство
О чём код?
#include "core/font_texture.hpp" #include "core/exception.hpp" #include "core/texture_settings.hpp" #include "division_engine_core/font.h" #include "division_engine_core/types/texture.h" #include "rect.hpp" #include <cstdio> #include <cstdlib> #include <cstring> #include <iterator> #include <random> #include <stdint.h> #include <utility> #define STB_RECT_PACK_IMPLEMENTATION #include <stb_rect_pack.h> namespace division_engine::core { const size_t RESERVE_GLYPH_CACHE_SIZE = 30; FontTexture::FontTexture( Context& context, const std::filesystem::path& font_path, size_t font_size, glm::ivec2 resolution ) : _character_to_glyph_index() , _glyphs() , _glyph_sdf() , _ctx(context) , _resolution(resolution) , _pixel_buffer(static_cast<uint8_t*>(std::malloc(resolution.x * resolution.y))) , _stbrp_ctx(static_cast<stbrp_context*>(malloc(sizeof(stbrp_context)))) , _stbrp_nodes(static_cast<stbrp_node*>(malloc(sizeof(stbrp_node) * resolution.x))) , _font_id(_ctx.create_font(font_path, static_cast<uint32_t>(font_size))) , _texture_id(context.create_texture(TextureSettings(resolution, DIVISION_TEXTURE_FORMAT_R8Uint) .with_min_mag_filter( DIVISION_TEXTURE_MIN_MAG_FILTER_LINEAR, DIVISION_TEXTURE_MIN_MAG_FILTER_LINEAR ))) , _texture_was_changed(false) { std::memset(_pixel_buffer, 0, resolution.x * resolution.y); _glyphs.reserve(RESERVE_GLYPH_CACHE_SIZE); _glyph_sdf.reserve(RESERVE_GLYPH_CACHE_SIZE); _character_to_glyph_index.reserve(RESERVE_GLYPH_CACHE_SIZE); stbrp_init_target(_stbrp_ctx, resolution.x, resolution.y, _stbrp_nodes, resolution.x); } FontTexture::~FontTexture() { if (!_pixel_buffer) return; _ctx.delete_texture(_texture_id); _ctx.delete_font(_font_id); std::free(_pixel_buffer); } int32_t FontTexture::line_height() const { return static_cast<int32_t>(division_engine_font_get_line_height(_ctx.get_ptr(), _font_id)); } void FontTexture::upload_texture() { if (!_texture_was_changed) { return; } _ctx.set_texture_data(_texture_id, _pixel_buffer); _texture_was_changed = false; } size_t FontTexture::reserve_character(char32_t character) { auto it = _character_to_glyph_index.find(character); if (it != _character_to_glyph_index.end()) { return it->second; } size_t new_index = _character_to_glyph_index.size(); layout_glyph(character, new_index); _character_to_glyph_index.emplace(std::make_pair(character, new_index)); return new_index; } void FontTexture::layout_glyph(char32_t character, size_t index) { const auto insert_index = static_cast<decltype(_glyphs)::difference_type>(index); const uint8_t* sdf_buffer; // NOLINT DivisionFontGlyph glyph; if (!division_engine_font_render_sdf_glyph( _ctx.get_ptr(), _font_id, static_cast<int32_t>(character), &sdf_buffer, &glyph )) { throw new Exception { "Failed to make sdf texture for glyph" }; } stbrp_rect rp_rect; rp_rect.w = static_cast<int>(glyph.width); rp_rect.h = static_cast<int>(glyph.height); if (!stbrp_pack_rects(_stbrp_ctx, &rp_rect, 1)) { throw FontTextureOutOfFreeSpaceException {}; } _glyphs.insert(_glyphs.begin() + insert_index, glyph); _glyph_sdf.insert( _glyph_sdf.begin() + insert_index, Rect::from_top_left({ rp_rect.x, rp_rect.y }, { rp_rect.w, rp_rect.h }) ); for (int h = 0; h < glyph.height; h++) { auto src_row_start = glyph.width * h; auto dst_row_start = rp_rect.x + (rp_rect.y + h) * _resolution.x; const auto* src_ptr = sdf_buffer + src_row_start; auto* dst_ptr = _pixel_buffer + dst_row_start; std::memcpy(dst_ptr, src_ptr, glyph.width); } _texture_was_changed = true; } }