#pragma once /* * Copyright (C) 2024 Brett Terpstra * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BLT_WITH_GRAPHICS_FONT_RENDERER_H #define BLT_WITH_GRAPHICS_FONT_RENDERER_H #include #include #include #include #include #include namespace blt::gfx { class font_texture_atlas : public texture_gl2D { public: struct bounded_t { font::glyph_t glyph; // starting point inside texture atlas blt::vec2ui min; // ending point of the glyph, inside texture atlas blt::vec2ui max; }; struct added_font_results_t { blt::u64 last_inserted_index; blt::u64 min_index_used; blt::u64 max_index_used; }; public: explicit font_texture_atlas(blt::i32 dimensions, blt::u32 padding); added_font_results_t add_font(const font::font_file_t& file, float size); added_font_results_t add_font(const font::font_file_t& file, blt::u64 start, float size); bounded_t& get_glyph(blt::u64 c, float size) { return glyphs.at(size).at(c); } [[nodiscard]] const bounded_t& get_glyph(blt::u64 c, float size) const { return glyphs.at(size).at(c); } private: blt::hashmap_t> glyphs; blt::u32 used_width = 0; blt::u32 used_height = 0; blt::u32 padding; }; class font_generator_t { public: struct bounded_font_t { std::unique_ptr atlas; float min_size, max_size; blt::u64 min_char, max_char; bounded_font_t(std::unique_ptr atlas, float minSize, float maxSize, u64 minChar, u64 maxChar): atlas(std::move(atlas)), min_size(minSize), max_size(maxSize), min_char(minChar), max_char(maxChar) {} }; public: explicit font_generator_t(blt::i32 dimensions, blt::u32 padding, const std::vector& sizes_to_generate); void add_font(const font::font_file_t& file); inline font_texture_atlas& get_texture(float size, blt::u64 c) { for (auto& atlas : atlases) { if (!(size >= atlas.min_size && size <= atlas.max_size)) continue; if (c >= atlas.min_char && c <= atlas.max_char) return *atlas.atlas; } throw std::runtime_error("Character not found inside atlases at this size"); } [[nodiscard]] blt::i32 get_dimensions() const { return dimensions; } private: blt::i32 dimensions; blt::u32 padding; std::vector atlases; // doesn't make sense to store this. std::vector sizes_to_generate; }; class font_renderer_t { public: struct compiled_text_t { friend font_renderer_t; public: explicit compiled_text_t(font_generator_t& generator); void change_text(std::string_view str, float size); compiled_text_t& setPosition(const blt::vec2f& pos) { position = pos; return *this; } compiled_text_t& setScale(const blt::vec2f& s) { scale = s; return *this; } compiled_text_t& setColor(const blt::vec4f& c) { color = c; return *this; } compiled_text_t& setPosition(float x, float y) { position = {x, y}; return *this; } compiled_text_t& setScale(float x, float y) { scale = {x, y}; return *this; } compiled_text_t& setColor(float r, float g, float b, float a = 1) { color = {r, g, b, a}; return *this; } compiled_text_t& setZIndex(float s) { z_index = s; return *this; } [[nodiscard]] const vec2f& getPosition() const { return position; } [[nodiscard]] const vec2f& getScale() const { return scale; } [[nodiscard]] const vec4f& getColor() const { return color; } [[nodiscard]] float getZIndex() const { return z_index; } private: void draw(); struct text_render_info_t { font_texture_atlas* texture = nullptr; blt::size_t render_start = 0; blt::size_t render_count = 0; text_render_info_t(font_texture_atlas* texture, size_t renderStart, size_t renderCount): texture(texture), render_start(renderStart), render_count(renderCount) {} }; font_generator_t& generator; vertex_array_t vao{}; std::vector renders; blt::vec2f position; blt::vec2f scale = {1, 1}; blt::vec4 color = blt::make_color(1, 1, 1); float z_index = 0; }; public: explicit font_renderer_t(); void create_default(blt::i32 dimensions = 0); void create(const std::vector& generated_font_sizes, blt::i32 dimensions = 0); void cleanup(); void add_font(const font::font_file_t& file) { generator->add_font(file); } void add_default_font(std::string_view path); void add_default_font(const blt::u8* data, blt::size_t size, bool compressed = false); compiled_text_t* create_text(std::string_view str, float size); void destroy_text(compiled_text_t* text); void render(); private: std::unique_ptr generator; std::unique_ptr font_shader; blt::hashmap_t text_ptr_to_index; std::vector> added_texts; std::vector> cached_text_objects; }; } #endif //BLT_WITH_GRAPHICS_FONT_RENDERER_H