font rendering
parent
ed6f36020e
commit
f75cbbb10c
|
@ -1,7 +1,7 @@
|
||||||
cmake_minimum_required(VERSION 3.25)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
|
|
||||||
set(BLT_GRAPHICS_VERSION 1.0.10)
|
set(BLT_GRAPHICS_VERSION 1.0.11)
|
||||||
set(BLT_GRAPHICS_TEST_VERSION 0.0.1)
|
set(BLT_GRAPHICS_TEST_VERSION 0.0.1)
|
||||||
|
|
||||||
project(BLT_WITH_GRAPHICS VERSION ${BLT_GRAPHICS_VERSION})
|
project(BLT_WITH_GRAPHICS VERSION ${BLT_GRAPHICS_VERSION})
|
||||||
|
|
|
@ -40,23 +40,25 @@ namespace blt::gfx::font
|
||||||
class font_face_t
|
class font_face_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit font_face_t(std::string_view path);
|
explicit font_face_t(std::string_view path, std::string_view font_name);
|
||||||
|
|
||||||
explicit font_face_t(const blt::u8* data, blt::size_t size, bool compressed = false);
|
explicit font_face_t(std::string_view font_name, const blt::u8* data, blt::size_t size, bool compressed = false);
|
||||||
|
|
||||||
void set_pixel_sizes(blt::u32 width, blt::u32 height) const;
|
void set_pixel_sizes(blt::u32 width, blt::u32 height) const;
|
||||||
|
|
||||||
[[nodiscard]] std::optional<int> load_char(FT_ULong c) const;
|
[[nodiscard]] std::optional<int> load_char(FT_ULong c) const;
|
||||||
|
|
||||||
[[nodiscard]] FT_Face* get() const
|
[[nodiscard]] FT_Face* get() const
|
||||||
{
|
{ return face.get(); }
|
||||||
return face.get();
|
|
||||||
}
|
[[nodiscard]] std::string_view get_name() const
|
||||||
|
{ return font_name; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// decompressed data ownership
|
// decompressed data ownership
|
||||||
std::shared_ptr<blt::u8[]> internal_uncompressed_data;
|
std::shared_ptr<blt::u8[]> internal_uncompressed_data;
|
||||||
std::shared_ptr<FT_Face> face;
|
std::shared_ptr<FT_Face> face;
|
||||||
|
std::string font_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct font_file_t
|
struct font_file_t
|
||||||
|
|
|
@ -53,14 +53,14 @@ namespace blt::gfx
|
||||||
|
|
||||||
added_font_results_t add_font(const font::font_file_t& file, blt::u64 start, 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)
|
bounded_t& get_glyph(blt::u64 c, std::string_view font)
|
||||||
{ return glyphs.at(size).at(c); }
|
{ return glyphs.at(font).at(c); }
|
||||||
|
|
||||||
[[nodiscard]] const bounded_t& get_glyph(blt::u64 c, float size) const
|
[[nodiscard]] const bounded_t& get_glyph(blt::u64 c, std::string_view font) const
|
||||||
{ return glyphs.at(size).at(c); }
|
{ return glyphs.at(font).at(c); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
blt::hashmap_t<float, blt::hashmap_t<blt::u64, bounded_t>> glyphs;
|
blt::hashmap_t<std::string, blt::hashmap_t<blt::u64, bounded_t>> glyphs;
|
||||||
blt::u32 used_width = 0;
|
blt::u32 used_width = 0;
|
||||||
blt::u32 used_height = 0;
|
blt::u32 used_height = 0;
|
||||||
blt::u32 padding;
|
blt::u32 padding;
|
||||||
|
@ -78,45 +78,41 @@ namespace blt::gfx
|
||||||
|
|
||||||
struct bounded_font_t
|
struct bounded_font_t
|
||||||
{
|
{
|
||||||
std::unique_ptr<font_texture_atlas> atlas;
|
font_texture_atlas* atlas;
|
||||||
// float min_size, max_size;
|
blt::u64 min_char, max_char;
|
||||||
// blt::u64 min_char, max_char;
|
|
||||||
std::vector<size_bounds_t> size_limits;
|
|
||||||
|
|
||||||
explicit bounded_font_t(std::unique_ptr<font_texture_atlas> atlas): atlas(std::move(atlas))
|
bounded_font_t(font_texture_atlas* atlas, u64 minChar, u64 maxChar): atlas(atlas), min_char(minChar), max_char(maxChar)
|
||||||
{}
|
{}
|
||||||
// bounded_font_t(std::unique_ptr<font_texture_atlas> atlas, float minSize, float maxSize, u64 minChar, u64 maxChar):
|
// replace with font -> char range. use scaling.
|
||||||
// atlas(std::move(atlas)), min_size(minSize), max_size(maxSize), min_char(minChar), max_char(maxChar)
|
|
||||||
// {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit font_generator_t(blt::i32 dimensions, blt::u32 padding, const std::vector<float>& sizes_to_generate);
|
explicit font_generator_t(blt::i32 dimensions, blt::u32 padding, float gen_size);
|
||||||
|
|
||||||
void add_font(const font::font_file_t& file);
|
void add_font(const font::font_file_t& file);
|
||||||
|
|
||||||
inline font_texture_atlas& get_texture(float size, blt::u64 c)
|
inline font_texture_atlas& get_texture(const std::string& font, blt::u64 c)
|
||||||
{
|
{
|
||||||
for (auto& atlas : atlases)
|
for (auto& atlas : font_associations[font])
|
||||||
{
|
{
|
||||||
BLT_TRACE("(%f %ld), %f %f, %ld %ld", size, c, atlas.min_size, atlas.max_size, atlas.min_char, atlas.max_char);
|
|
||||||
if (!(size >= atlas.min_size && size <= atlas.max_size))
|
|
||||||
continue;
|
|
||||||
if (c >= atlas.min_char && c <= atlas.max_char)
|
if (c >= atlas.min_char && c <= atlas.max_char)
|
||||||
return *atlas.atlas;
|
return *atlas.atlas;
|
||||||
}
|
}
|
||||||
throw std::runtime_error("Character not found inside atlases at this size");
|
throw std::runtime_error("Character not found inside atlases with font '" + font + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] blt::i32 get_dimensions() const
|
[[nodiscard]] blt::i32 get_dimensions() const
|
||||||
{ return dimensions; }
|
{ return dimensions; }
|
||||||
|
|
||||||
|
[[nodiscard]] float get_generated_size() const
|
||||||
|
{ return gen_size; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
blt::i32 dimensions;
|
blt::i32 dimensions;
|
||||||
blt::u32 padding;
|
blt::u32 padding;
|
||||||
std::vector<bounded_font_t> atlases;
|
std::vector<std::unique_ptr<font_texture_atlas>> atlases;
|
||||||
// doesn't make sense to store this.
|
blt::hashmap_t<std::string, std::vector<bounded_font_t>> font_associations;
|
||||||
std::vector<float> sizes_to_generate;
|
float gen_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
class font_renderer_t
|
class font_renderer_t
|
||||||
|
@ -126,9 +122,9 @@ namespace blt::gfx
|
||||||
{
|
{
|
||||||
friend font_renderer_t;
|
friend font_renderer_t;
|
||||||
public:
|
public:
|
||||||
explicit compiled_text_t(font_generator_t& generator);
|
compiled_text_t& setText(std::string_view str, float size, std::string_view font = "__default");
|
||||||
|
|
||||||
void change_text(std::string_view str, float size);
|
compiled_text_t& recompile();
|
||||||
|
|
||||||
compiled_text_t& setPosition(const blt::vec2f& pos)
|
compiled_text_t& setPosition(const blt::vec2f& pos)
|
||||||
{
|
{
|
||||||
|
@ -136,9 +132,22 @@ namespace blt::gfx
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
compiled_text_t& setScale(const blt::vec2f& s)
|
compiled_text_t& setBounds(const blt::vec2f& limit)
|
||||||
{
|
{
|
||||||
scale = s;
|
bounds = limit;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
compiled_text_t& setUnrestrictedBounds()
|
||||||
|
{
|
||||||
|
bounds = {};
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
compiled_text_t& setSize(float size)
|
||||||
|
{
|
||||||
|
current_size = size;
|
||||||
|
scale = {size / generator.get_generated_size(), size / generator.get_generated_size()};
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,12 +163,6 @@ namespace blt::gfx
|
||||||
return *this;
|
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)
|
compiled_text_t& setColor(float r, float g, float b, float a = 1)
|
||||||
{
|
{
|
||||||
color = {r, g, b, a};
|
color = {r, g, b, a};
|
||||||
|
@ -172,6 +175,9 @@ namespace blt::gfx
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const vec2f& getBounds() const
|
||||||
|
{ return bounds; }
|
||||||
|
|
||||||
[[nodiscard]] const vec2f& getPosition() const
|
[[nodiscard]] const vec2f& getPosition() const
|
||||||
{ return position; }
|
{ return position; }
|
||||||
|
|
||||||
|
@ -185,6 +191,8 @@ namespace blt::gfx
|
||||||
{ return z_index; }
|
{ return z_index; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
explicit compiled_text_t(font_generator_t& generator);
|
||||||
|
|
||||||
void draw();
|
void draw();
|
||||||
|
|
||||||
struct text_render_info_t
|
struct text_render_info_t
|
||||||
|
@ -199,10 +207,10 @@ namespace blt::gfx
|
||||||
};
|
};
|
||||||
|
|
||||||
font_generator_t& generator;
|
font_generator_t& generator;
|
||||||
std::string contents;
|
std::string contents, font;
|
||||||
vertex_array_t vao{};
|
vertex_array_t vao{};
|
||||||
std::vector<text_render_info_t> renders;
|
std::vector<text_render_info_t> renders;
|
||||||
blt::vec2f position;
|
blt::vec2f position, bounds;
|
||||||
blt::vec2f scale = {1, 1};
|
blt::vec2f scale = {1, 1};
|
||||||
blt::vec4 color = blt::make_color(1, 1, 1);
|
blt::vec4 color = blt::make_color(1, 1, 1);
|
||||||
float z_index = 0;
|
float z_index = 0;
|
||||||
|
@ -212,9 +220,9 @@ namespace blt::gfx
|
||||||
public:
|
public:
|
||||||
explicit font_renderer_t();
|
explicit font_renderer_t();
|
||||||
|
|
||||||
void create_default(blt::i32 dimensions = 0);
|
void create_default(float gen_size = 250, blt::i32 dimensions = 0);
|
||||||
|
|
||||||
void create(const std::vector<float>& generated_font_sizes, blt::i32 dimensions = 0);
|
void create(float gen_size, blt::i32 dimensions = 0);
|
||||||
|
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
|
||||||
|
@ -223,11 +231,11 @@ namespace blt::gfx
|
||||||
generator->add_font(file);
|
generator->add_font(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_default_font(std::string_view path);
|
void add_default_font(std::string_view path, std::string_view name = "__default");
|
||||||
|
|
||||||
void add_default_font(const blt::u8* data, blt::size_t size, bool compressed = false);
|
void add_default_font(const blt::u8* data, blt::size_t size, bool compressed = false, std::string_view name = "__default");
|
||||||
|
|
||||||
compiled_text_t* create_text(std::string_view str, float size);
|
compiled_text_t* create_text(std::string_view str, float size, std::string_view font = "__default");
|
||||||
|
|
||||||
void destroy_text(compiled_text_t* text);
|
void destroy_text(compiled_text_t* text);
|
||||||
|
|
||||||
|
|
|
@ -208,8 +208,9 @@ namespace blt::gfx::font
|
||||||
FT_Done_FreeType(*lib);
|
FT_Done_FreeType(*lib);
|
||||||
}
|
}
|
||||||
|
|
||||||
font_face_t::font_face_t(std::string_view path)
|
font_face_t::font_face_t(std::string_view path, std::string_view name)
|
||||||
{
|
{
|
||||||
|
font_name = name;
|
||||||
face = std::shared_ptr<FT_Face>(new FT_Face{}, [](FT_Face* ptr) {
|
face = std::shared_ptr<FT_Face>(new FT_Face{}, [](FT_Face* ptr) {
|
||||||
FT_Done_Face(*ptr);
|
FT_Done_Face(*ptr);
|
||||||
delete ptr;
|
delete ptr;
|
||||||
|
@ -224,8 +225,9 @@ namespace blt::gfx::font
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
font_face_t::font_face_t(const blt::u8* data, blt::size_t size, bool compressed)
|
font_face_t::font_face_t(std::string_view name, const blt::u8* data, blt::size_t size, bool compressed)
|
||||||
{
|
{
|
||||||
|
font_name = name;
|
||||||
face = std::shared_ptr<FT_Face>(new FT_Face{}, [](FT_Face* ptr) {
|
face = std::shared_ptr<FT_Face>(new FT_Face{}, [](FT_Face* ptr) {
|
||||||
FT_Done_Face(*ptr);
|
FT_Done_Face(*ptr);
|
||||||
delete ptr;
|
delete ptr;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <blt/gfx/renderer/shaders/2d_font.vert>
|
#include <blt/gfx/renderer/shaders/2d_font.vert>
|
||||||
#include <blt/gfx/renderer/shaders/2d_font.frag>
|
#include <blt/gfx/renderer/shaders/2d_font.frag>
|
||||||
#include <blt/gfx/shader.h>
|
#include <blt/gfx/shader.h>
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
// TODO: signed distance fonts
|
// TODO: signed distance fonts
|
||||||
//#include <msdfgen.h>
|
//#include <msdfgen.h>
|
||||||
|
@ -85,7 +86,7 @@ namespace blt::gfx
|
||||||
upload(face->glyph->bitmap.buffer, GL_RED, 0, static_cast<blt::i32>(begin_width), static_cast<blt::i32>(begin_height),
|
upload(face->glyph->bitmap.buffer, GL_RED, 0, static_cast<blt::i32>(begin_width), static_cast<blt::i32>(begin_height),
|
||||||
static_cast<blt::i32>(width), static_cast<blt::i32>(height), GL_UNSIGNED_BYTE);
|
static_cast<blt::i32>(width), static_cast<blt::i32>(height), GL_UNSIGNED_BYTE);
|
||||||
|
|
||||||
glyphs[size].insert(std::pair{i, bounded_t{
|
glyphs[file.font.get_name()].insert(std::pair{i, bounded_t{
|
||||||
font::glyph_t{
|
font::glyph_t{
|
||||||
{width, height},
|
{width, height},
|
||||||
{face->glyph->bitmap_left, face->glyph->bitmap_top},
|
{face->glyph->bitmap_left, face->glyph->bitmap_top},
|
||||||
|
@ -98,52 +99,36 @@ namespace blt::gfx
|
||||||
return {-1ul, min_index_used, max_index_used};
|
return {-1ul, min_index_used, max_index_used};
|
||||||
}
|
}
|
||||||
|
|
||||||
font_generator_t::font_generator_t(blt::i32 dimensions, blt::u32 padding, const std::vector<float>& sizes_to_generate):
|
font_generator_t::font_generator_t(blt::i32 dimensions, blt::u32 padding, float gen_size):
|
||||||
dimensions(dimensions), padding(padding), sizes_to_generate(sizes_to_generate)
|
dimensions(dimensions), padding(padding), gen_size(gen_size)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void font_generator_t::add_font(const font::font_file_t& file)
|
void font_generator_t::add_font(const font::font_file_t& file)
|
||||||
{
|
{
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
float min_size = std::numeric_limits<float>::max();
|
|
||||||
float max_size = 0;
|
|
||||||
for (const auto& size : sizes_to_generate)
|
|
||||||
{
|
|
||||||
min_size = std::min(size, min_size);
|
|
||||||
max_size = std::max(size, max_size);
|
|
||||||
auto& vec = atlases;
|
auto& vec = atlases;
|
||||||
|
|
||||||
if (vec.empty())
|
if (atlases.empty())
|
||||||
vec.emplace_back(std::make_unique<font_texture_atlas>(dimensions, padding), min_size, max_size, file.character_min_index, 0);
|
atlases.emplace_back(std::make_unique<font_texture_atlas>(dimensions, padding));
|
||||||
|
auto& font_vec = font_associations[file.font.get_name()];
|
||||||
|
|
||||||
blt::u64 start_index = file.character_min_index;
|
blt::u64 start_index = file.character_min_index;
|
||||||
while (start_index != -1ul)
|
while (start_index != -1ul)
|
||||||
{
|
{
|
||||||
auto results = vec.back().atlas->add_font(file, start_index, size);
|
// add font and associate results with a font file
|
||||||
vec.back().min_char = results.min_index_used;
|
auto results = atlases.back()->add_font(file, start_index, gen_size);
|
||||||
vec.back().max_char = results.max_index_used;
|
font_vec.emplace_back(atlases.back().get(), results.min_index_used, results.max_index_used);
|
||||||
vec.back().min_size = min_size;
|
// didn't fit, need to push new atlas
|
||||||
vec.back().max_size = max_size;
|
|
||||||
if (results.last_inserted_index != -1ul)
|
if (results.last_inserted_index != -1ul)
|
||||||
{
|
vec.emplace_back(std::make_unique<font_texture_atlas>(dimensions, padding));
|
||||||
vec.emplace_back(std::make_unique<font_texture_atlas>(dimensions, padding), min_size, max_size, start_index, 0);
|
|
||||||
min_size = size;
|
|
||||||
max_size = size;
|
|
||||||
}
|
|
||||||
start_index = results.last_inserted_index;
|
start_index = results.last_inserted_index;
|
||||||
// BLT_INFO("%f, %ld", size, start_index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||||
// BLT_TRACE(atlases.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern float square_vertices[20];
|
|
||||||
extern const unsigned int square_indices[6];
|
|
||||||
|
|
||||||
font_renderer_t::font_renderer_t() = default;
|
font_renderer_t::font_renderer_t() = default;
|
||||||
|
|
||||||
void font_renderer_t::create(const std::vector<float>& generated_font_sizes, blt::i32 dimensions)
|
void font_renderer_t::create(float gen_size, blt::i32 dimensions)
|
||||||
{
|
{
|
||||||
font_shader = shader_t::make_unique(shader_2d_font_vert, shader_2d_font_frag);
|
font_shader = shader_t::make_unique(shader_2d_font_vert, shader_2d_font_frag);
|
||||||
font_shader->bind();
|
font_shader->bind();
|
||||||
|
@ -156,7 +141,14 @@ namespace blt::gfx
|
||||||
dimensions = std::min(size, 2048);
|
dimensions = std::min(size, 2048);
|
||||||
BLT_INFO("Max texture size %d, font renderer will use size %d", size, dimensions);
|
BLT_INFO("Max texture size %d, font renderer will use size %d", size, dimensions);
|
||||||
}
|
}
|
||||||
generator = std::make_unique<font_generator_t>(dimensions, 2, generated_font_sizes);
|
generator = std::make_unique<font_generator_t>(dimensions, 2, gen_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void font_renderer_t::create_default(float gen_size, blt::i32 dimensions)
|
||||||
|
{
|
||||||
|
create(gen_size, dimensions);
|
||||||
|
|
||||||
|
add_default_font(reinterpret_cast<const blt::u8*>(font::default_font_compressed_data), font::default_font_compressed_size, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void font_renderer_t::cleanup()
|
void font_renderer_t::cleanup()
|
||||||
|
@ -173,7 +165,7 @@ namespace blt::gfx
|
||||||
blt::gfx::font::cleanup();
|
blt::gfx::font::cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
font_renderer_t::compiled_text_t* font_renderer_t::create_text(std::string_view str, float size)
|
font_renderer_t::compiled_text_t* font_renderer_t::create_text(std::string_view str, float size, std::string_view font)
|
||||||
{
|
{
|
||||||
std::unique_ptr<font_renderer_t::compiled_text_t> ptr;
|
std::unique_ptr<font_renderer_t::compiled_text_t> ptr;
|
||||||
if (!cached_text_objects.empty())
|
if (!cached_text_objects.empty())
|
||||||
|
@ -182,9 +174,9 @@ namespace blt::gfx
|
||||||
cached_text_objects.erase(cached_text_objects.begin());
|
cached_text_objects.erase(cached_text_objects.begin());
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
ptr = std::make_unique<compiled_text_t>(*generator);
|
ptr = std::unique_ptr<compiled_text_t>(new compiled_text_t{*generator});
|
||||||
}
|
}
|
||||||
ptr->change_text(str, size);
|
ptr->setText(str, size, font);
|
||||||
auto index = added_texts.size();
|
auto index = added_texts.size();
|
||||||
added_texts.push_back(std::move(ptr));
|
added_texts.push_back(std::move(ptr));
|
||||||
text_ptr_to_index[added_texts.back().get()] = index;
|
text_ptr_to_index[added_texts.back().get()] = index;
|
||||||
|
@ -218,90 +210,30 @@ namespace blt::gfx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void font_renderer_t::create_default(blt::i32 dimensions)
|
void font_renderer_t::add_default_font(std::string_view path, std::string_view name)
|
||||||
{
|
{
|
||||||
create({9, 11, 12, 13, 14, 16, 18, 24, 32, 36, 40, 48, 52, 64, 72, 96, 106, 250}, dimensions);
|
font::font_face_t default_font_face{path, name};
|
||||||
|
|
||||||
add_default_font(reinterpret_cast<const blt::u8*>(font::default_font_compressed_data), font::default_font_compressed_size, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void font_renderer_t::add_default_font(std::string_view path)
|
|
||||||
{
|
|
||||||
font::font_face_t default_font_face{path};
|
|
||||||
font::font_file_t default_font{default_font_face, 0, 128};
|
font::font_file_t default_font{default_font_face, 0, 128};
|
||||||
add_font(default_font);
|
add_font(default_font);
|
||||||
}
|
}
|
||||||
|
|
||||||
void font_renderer_t::add_default_font(const blt::u8* data, blt::size_t size, bool compressed)
|
void font_renderer_t::add_default_font(const blt::u8* data, blt::size_t size, bool compressed, std::string_view name)
|
||||||
{
|
{
|
||||||
font::font_face_t default_font_face{data, size, compressed};
|
font::font_face_t default_font_face{name, data, size, compressed};
|
||||||
font::font_file_t default_font{default_font_face, 0, 128};
|
font::font_file_t default_font{default_font_face, 0, 128};
|
||||||
add_font(default_font);
|
add_font(default_font);
|
||||||
}
|
}
|
||||||
|
|
||||||
void font_renderer_t::compiled_text_t::change_text(std::string_view str, float size)
|
font_renderer_t::compiled_text_t& font_renderer_t::compiled_text_t::setText(std::string_view str, float size, std::string_view f)
|
||||||
{
|
{
|
||||||
if (str == contents)
|
if (str == contents)
|
||||||
return;
|
return *this;
|
||||||
|
|
||||||
contents = str;
|
contents = str;
|
||||||
current_size = size;
|
font = f;
|
||||||
static std::vector<float> vertices;
|
setSize(size);
|
||||||
vertices.clear();
|
recompile();
|
||||||
renders.clear();
|
return *this;
|
||||||
|
|
||||||
font_texture_atlas* last_texture = nullptr;
|
|
||||||
blt::size_t draw_start = 0;
|
|
||||||
blt::size_t draw_count = 0;
|
|
||||||
|
|
||||||
float x = 0;
|
|
||||||
// TODO: parker UTF8
|
|
||||||
for (const auto& c : str)
|
|
||||||
{
|
|
||||||
auto& texture = generator.get_texture(size, c);
|
|
||||||
|
|
||||||
if (last_texture == nullptr)
|
|
||||||
last_texture = &texture;
|
|
||||||
else if (last_texture != &texture)
|
|
||||||
{
|
|
||||||
renders.emplace_back(last_texture, draw_start, draw_count);
|
|
||||||
draw_start += draw_count;
|
|
||||||
draw_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& ch = texture.get_glyph(c, size);
|
|
||||||
auto dims = static_cast<float>(generator.get_dimensions());
|
|
||||||
|
|
||||||
float x_pos = x + static_cast<float>(ch.glyph.bearing.x());
|
|
||||||
float y_pos = -static_cast<float>(ch.glyph.size.y() - ch.glyph.bearing.y());
|
|
||||||
|
|
||||||
auto w = static_cast<float>(ch.glyph.size.x());
|
|
||||||
auto h = static_cast<float>(ch.glyph.size.y());
|
|
||||||
|
|
||||||
auto texture_min_x = static_cast<float>(ch.min.x()) / dims;
|
|
||||||
auto texture_min_y = static_cast<float>(ch.min.y()) / dims;
|
|
||||||
auto texture_max_x = static_cast<float>(ch.max.x()) / dims;
|
|
||||||
auto texture_max_y = static_cast<float>(ch.max.y()) / dims;
|
|
||||||
|
|
||||||
// BLT_TRACE("%c: %f | xy[%f %f] wh[%f %f] | min[%f %f] max[%f %f] |", c, x, x_pos, y_pos, w, h, texture_min_x, texture_min_y, texture_max_x, texture_max_y);
|
|
||||||
|
|
||||||
std::array<float, 6 * 4> local_vert = {
|
|
||||||
x_pos, y_pos + h, texture_min_x, texture_min_y,
|
|
||||||
x_pos, y_pos, texture_min_x, texture_max_y,
|
|
||||||
x_pos + w, y_pos, texture_max_x, texture_max_y,
|
|
||||||
|
|
||||||
x_pos, y_pos + h, texture_min_x, texture_min_y,
|
|
||||||
x_pos + w, y_pos, texture_max_x, texture_max_y,
|
|
||||||
x_pos + w, y_pos + h, texture_max_x, texture_min_y
|
|
||||||
};
|
|
||||||
vertices.insert(vertices.end(), local_vert.begin(), local_vert.end());
|
|
||||||
draw_count += 6;
|
|
||||||
x += static_cast<float>(ch.glyph.advance >> 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
// BLT_TRACE("size: %ld %ld %ld", draw_count, vertices.size(), vertices.size() / 4);
|
|
||||||
|
|
||||||
renders.emplace_back(last_texture, draw_start, draw_count);
|
|
||||||
vao.getBuffer(0).update(static_cast<long>(vertices.size() * sizeof(float)), vertices.data());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
font_renderer_t::compiled_text_t::compiled_text_t(font_generator_t& generator): generator(generator)
|
font_renderer_t::compiled_text_t::compiled_text_t(font_generator_t& generator): generator(generator)
|
||||||
|
@ -330,5 +262,115 @@ namespace blt::gfx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct word_t
|
||||||
|
{
|
||||||
|
std::vector<float> vertices;
|
||||||
|
float x = 0;
|
||||||
|
|
||||||
|
void apply(std::vector<float>& out)
|
||||||
|
{
|
||||||
|
for (float v : vertices)
|
||||||
|
out.push_back(v + x);
|
||||||
|
vertices.clear();
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct position_tracker_t
|
||||||
|
{
|
||||||
|
float global_x = 0, global_y = 0;
|
||||||
|
|
||||||
|
void newline(float line_size)
|
||||||
|
{
|
||||||
|
global_y -= line_size;
|
||||||
|
global_x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void advance(blt::u64 size)
|
||||||
|
{
|
||||||
|
global_x += static_cast<float>(size >> 6);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
font_renderer_t::compiled_text_t& font_renderer_t::compiled_text_t::recompile()
|
||||||
|
{
|
||||||
|
static std::vector<float> vertices;
|
||||||
|
static word_t current_word;
|
||||||
|
vertices.clear();
|
||||||
|
renders.clear();
|
||||||
|
|
||||||
|
font_texture_atlas* last_texture = nullptr;
|
||||||
|
blt::size_t draw_start = 0;
|
||||||
|
blt::size_t draw_count = 0;
|
||||||
|
|
||||||
|
position_tracker_t current_pos;
|
||||||
|
// TODO: parker UTF8
|
||||||
|
for (const auto& c : contents)
|
||||||
|
{
|
||||||
|
// std::cout << "C: " << c << " || " << static_cast<int>(c) << std::endl;
|
||||||
|
if (c == '\n')
|
||||||
|
{
|
||||||
|
current_pos.newline(generator.get_generated_size());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto& texture = generator.get_texture(std::string(font), c);
|
||||||
|
auto& ch = texture.get_glyph(c, font);
|
||||||
|
|
||||||
|
// if (std::isblank(c))
|
||||||
|
// {
|
||||||
|
// if (bounds.x() > 0 && current_pos.global_x + current_word.x > bounds.x())
|
||||||
|
// current_pos.newline(generator.get_generated_size());
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
if (std::isspace(c))
|
||||||
|
current_word.apply(vertices);
|
||||||
|
|
||||||
|
if (last_texture == nullptr)
|
||||||
|
last_texture = &texture;
|
||||||
|
else if (last_texture != &texture)
|
||||||
|
{
|
||||||
|
renders.emplace_back(last_texture, draw_start, draw_count);
|
||||||
|
draw_start += draw_count;
|
||||||
|
draw_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dims = static_cast<float>(generator.get_dimensions());
|
||||||
|
|
||||||
|
float x_pos = current_pos.global_x + static_cast<float>(ch.glyph.bearing.x());
|
||||||
|
float y_pos = current_pos.global_y - static_cast<float>(ch.glyph.size.y() - ch.glyph.bearing.y());
|
||||||
|
|
||||||
|
auto w = static_cast<float>(ch.glyph.size.x());
|
||||||
|
auto h = static_cast<float>(ch.glyph.size.y());
|
||||||
|
|
||||||
|
auto texture_min_x = static_cast<float>(ch.min.x()) / dims;
|
||||||
|
auto texture_min_y = static_cast<float>(ch.min.y()) / dims;
|
||||||
|
auto texture_max_x = static_cast<float>(ch.max.x()) / dims;
|
||||||
|
auto texture_max_y = static_cast<float>(ch.max.y()) / dims;
|
||||||
|
|
||||||
|
// BLT_TRACE("%c: %f | xy[%f %f] wh[%f %f] | min[%f %f] max[%f %f] |", c, x, x_pos, y_pos, w, h, texture_min_x, texture_min_y, texture_max_x, texture_max_y);
|
||||||
|
|
||||||
|
std::array<float, 6 * 4> local_vert = {
|
||||||
|
x_pos, y_pos + h, texture_min_x, texture_min_y,
|
||||||
|
x_pos, y_pos, texture_min_x, texture_max_y,
|
||||||
|
x_pos + w, y_pos, texture_max_x, texture_max_y,
|
||||||
|
|
||||||
|
x_pos, y_pos + h, texture_min_x, texture_min_y,
|
||||||
|
x_pos + w, y_pos, texture_max_x, texture_max_y,
|
||||||
|
x_pos + w, y_pos + h, texture_max_x, texture_min_y
|
||||||
|
};
|
||||||
|
current_word.vertices.insert(current_word.vertices.end(), local_vert.begin(), local_vert.end());
|
||||||
|
|
||||||
|
draw_count += 6;
|
||||||
|
current_pos.advance(ch.glyph.advance);
|
||||||
|
}
|
||||||
|
current_word.apply(vertices);
|
||||||
|
|
||||||
|
// BLT_TRACE("size: %ld %ld %ld", draw_count, vertices.size(), vertices.size() / 4);
|
||||||
|
|
||||||
|
renders.emplace_back(last_texture, draw_start, draw_count);
|
||||||
|
vao.getBuffer(0).update(static_cast<long>(vertices.size() * sizeof(float)), vertices.data());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue