font rendering. rotation and immediate mode

main
Brett 2024-11-14 16:01:53 -05:00
parent 1afe267163
commit 0a0b87fc55
5 changed files with 185 additions and 40 deletions

View File

@ -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.12) set(BLT_GRAPHICS_VERSION 1.1.0)
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})

0
build_emscript.sh Executable file → Normal file
View File

View File

@ -119,17 +119,98 @@ namespace blt::gfx
class font_renderer_t class font_renderer_t
{ {
public: public:
struct render_context static constexpr blt::vec2f DEFAULT_SCALE{1, 1};
static constexpr blt::vec4 DEFAULT_COLOR = blt::make_color(0.8, 0.8, 0.8);
struct render_context_t
{ {
blt::vec2f position, bounds; blt::vec2f position, bounds;
blt::vec2f scale; blt::vec4 color = DEFAULT_COLOR;
blt::vec4 color; float z_index = 0;
float current_size = 0;
float rotation = 0;
explicit render_context_t(float current_size): current_size(current_size)
{}
render_context_t& setPosition(float x, float y)
{
position = {x, y};
return *this;
}
render_context_t& setPosition(const blt::vec2f& new_position)
{
position = new_position;
return *this;
}
render_context_t& setRotation(float r)
{
rotation = r;
return *this;
}
render_context_t& setColor(const blt::vec4f& new_color)
{
color = new_color;
return *this;
}
render_context_t& setColor(float r, float g, float b, float a = 1)
{
color = {r, g, b, a};
return *this;
}
render_context_t& setBounds(const blt::vec2f& new_bounds)
{
bounds = new_bounds;
return *this;
}
render_context_t& setBounds(float width, float height)
{
return setBounds({width, height});
}
render_context_t& setUnrestrictedBounds()
{
bounds = {};
return *this;
}
render_context_t& setSize(const float new_scale)
{
current_size = new_scale;
return *this;
}
render_context_t& setZIndex(float new_z_index)
{
z_index = new_z_index;
return *this;
}
[[nodiscard]] const vec2f& getPosition() const
{ return position; }
[[nodiscard]] const vec2f& getBounds() const
{ return bounds; }
[[nodiscard]] float getSize() const
{ return current_size; }
[[nodiscard]] float getRotation() const
{ return rotation; }
[[nodiscard]] const vec4& getColor() const
{ return color; }
}; };
struct text_index_t struct text_index_t
{ {
std::string text; std::string text;
float size;
std::string font; std::string font;
bool operator==(const text_index_t& rhs) const; bool operator==(const text_index_t& rhs) const;
@ -145,14 +226,28 @@ namespace blt::gfx
compiled_text_t& recompile(); compiled_text_t& recompile();
compiled_text_t& setPosition(float x, float y)
{
position = {x, y};
return *this;
}
compiled_text_t& setPosition(const blt::vec2f& pos) compiled_text_t& setPosition(const blt::vec2f& pos)
{ {
position = pos; position = pos;
return *this; return *this;
} }
compiled_text_t& setRotation(float r)
{
rotation = r;
return *this;
}
compiled_text_t& setBounds(const blt::vec2f& limit) compiled_text_t& setBounds(const blt::vec2f& limit)
{ {
if (limit == bounds)
return *this;
bounds = limit; bounds = limit;
recompile(); recompile();
return *this; return *this;
@ -175,12 +270,6 @@ namespace blt::gfx
return *this; return *this;
} }
compiled_text_t& setPosition(float x, float y)
{
position = {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};
@ -189,9 +278,13 @@ namespace blt::gfx
compiled_text_t& setSize(float size) compiled_text_t& setSize(float size)
{ {
if (current_size == size)
return *this;
current_size = size; current_size = size;
scale = {size / generator.get_generated_size(), size / generator.get_generated_size()}; scale = {size / generator.get_generated_size(), size / generator.get_generated_size()};
recompile(); // size only changes computation if there are bounds on the text.
if (bounds.x() != 0 || bounds.y() != 0)
recompile();
return *this; return *this;
} }
@ -216,9 +309,37 @@ namespace blt::gfx
[[nodiscard]] float getZIndex() const [[nodiscard]] float getZIndex() const
{ return z_index; } { return z_index; }
[[nodiscard]] float getRotation() const
{ return rotation; }
void save_to(render_context_t& save)
{
save.position = position;
save.bounds = bounds;
save.color = color;
save.z_index = z_index;
save.current_size = current_size;
save.rotation = rotation;
}
void restore_from(const render_context_t& restore)
{
setPosition(restore.position);
setBounds(restore.bounds);
setColor(restore.color);
setZIndex(restore.z_index);
setSize(restore.current_size);
setRotation(restore.rotation);
}
private: private:
explicit compiled_text_t(font_generator_t& generator); explicit compiled_text_t(font_generator_t& generator);
void bind() const
{
vao.bind();
}
void draw(); void draw();
struct text_render_info_t struct text_render_info_t
@ -237,10 +358,11 @@ namespace blt::gfx
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, bounds; blt::vec2f position, bounds;
blt::vec2f scale = {1, 1}; blt::vec2f scale = DEFAULT_SCALE;
blt::vec4 color = blt::make_color(0.8, 0.8, 0.8); blt::vec4 color = DEFAULT_COLOR;
float z_index = 0; float z_index = 0;
float current_size = 0; float current_size = 0;
float rotation = 0;
}; };
public: public:
@ -263,7 +385,7 @@ namespace blt::gfx
compiled_text_t* create_text(std::string_view str, float size, std::string_view font = "__default"); compiled_text_t* create_text(std::string_view str, float size, std::string_view font = "__default");
compiled_text_t* render_text(std::string_view str, float size, std::string_view font = "__default"); render_context_t& render_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);
@ -277,6 +399,7 @@ namespace blt::gfx
blt::hashmap_t<text_index_t, compiled_text_t*> rendered_strings; blt::hashmap_t<text_index_t, compiled_text_t*> rendered_strings;
blt::hashmap_t<compiled_text_t*, text_index_t> text_ptr_to_text_index; blt::hashmap_t<compiled_text_t*, text_index_t> text_ptr_to_text_index;
blt::hashmap_t<compiled_text_t*, std::vector<render_context_t>> render_list;
blt::hashset_t<compiled_text_t*> last_rendered_strings; blt::hashset_t<compiled_text_t*> last_rendered_strings;
blt::hashset_t<compiled_text_t*> currently_rendered_strings; blt::hashset_t<compiled_text_t*> currently_rendered_strings;
@ -304,7 +427,6 @@ struct std::hash<blt::gfx::font_renderer_t::text_index_t>
{ {
blt::size_t hash = 0; blt::size_t hash = 0;
blt::gfx::detail::hash_combine(hash, std::hash<std::string>{}(key.text)); blt::gfx::detail::hash_combine(hash, std::hash<std::string>{}(key.text));
blt::gfx::detail::hash_combine(hash, std::hash<float>{}(key.size));
blt::gfx::detail::hash_combine(hash, std::hash<std::string>{}(key.font)); blt::gfx::detail::hash_combine(hash, std::hash<std::string>{}(key.font));
return hash; return hash;

0
resources/fonts/a.out Executable file → Normal file
View File

View File

@ -201,28 +201,44 @@ namespace blt::gfx
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
for (auto [text, index] : text_ptr_to_index) for (auto [text, index] : text_ptr_to_index)
{ {
// stupid hack
if (text_ptr_to_text_index.find(text) != text_ptr_to_text_index.end())
continue;
text->bind();
blt::mat4x4 transform; blt::mat4x4 transform;
transform.translate(text->position); transform.translate(text->position);
transform.scale(text->scale); transform.scale(text->scale);
transform.rotateZ(blt::toRadians(text->rotation));
font_shader->setMatrix("transform", transform); font_shader->setMatrix("transform", transform);
font_shader->setFloat("z_index", text->z_index); font_shader->setFloat("z_index", text->z_index);
font_shader->setVec4("color", text->color); font_shader->setVec4("color", text->color);
text->draw(); text->draw();
} }
for (auto& text : currently_rendered_strings) for (auto& [text, list] : render_list)
{ {
blt::mat4x4 transform; text->bind();
transform.translate(text->position); render_context_t before{text->current_size};
transform.scale(text->scale); text->save_to(before);
font_shader->setMatrix("transform", transform); for (const auto& context : list)
font_shader->setFloat("z_index", text->z_index); {
font_shader->setVec4("color", text->color); text->restore_from(context);
text->draw();
blt::mat4x4 transform;
transform.translate(text->position);
transform.scale(text->scale);
transform.rotateZ(blt::toRadians(text->rotation));
font_shader->setMatrix("transform", transform);
font_shader->setFloat("z_index", text->z_index);
font_shader->setVec4("color", text->color);
text->draw();
}
text->restore_from(before);
if (last_rendered_strings.find(text) != last_rendered_strings.end()) if (last_rendered_strings.find(text) != last_rendered_strings.end())
last_rendered_strings.erase(text); last_rendered_strings.erase(text);
} }
render_list.clear();
for (auto& text : last_rendered_strings) for (auto& text : last_rendered_strings)
{ {
@ -231,6 +247,7 @@ namespace blt::gfx
cached_deallocated_text_objects.emplace_back(std::move(added_texts[text_ptr_to_index[text]])); cached_deallocated_text_objects.emplace_back(std::move(added_texts[text_ptr_to_index[text]]));
text_ptr_to_index.erase(text); text_ptr_to_index.erase(text);
} }
last_rendered_strings.clear();
for (auto& text : currently_rendered_strings) for (auto& text : currently_rendered_strings)
last_rendered_strings.insert(text); last_rendered_strings.insert(text);
@ -269,25 +286,32 @@ namespace blt::gfx
return ptr; return ptr;
} }
font_renderer_t::compiled_text_t* font_renderer_t::render_text(std::string_view str, float size, std::string_view font) font_renderer_t::render_context_t& font_renderer_t::render_text(std::string_view str, float size, std::string_view font)
{ {
auto str_iter = rendered_strings.find(text_index_t{std::string(str), size, std::string(font)}); auto str_iter = rendered_strings.find(text_index_t{std::string(str), std::string(font)});
compiled_text_t* ptr;
if (str_iter != rendered_strings.end()) if (str_iter != rendered_strings.end())
{ {
currently_rendered_strings.insert(str_iter->second); ptr = str_iter->second;
return str_iter->second; currently_rendered_strings.insert(ptr);
ptr->setSize(size);
} else
{
auto index = added_texts.size();
added_texts.emplace_back(allocate_text());
ptr = added_texts.back().get();
ptr->setText(str, size);
text_ptr_to_text_index[ptr] = text_index_t{std::string(str), std::string(font)};
rendered_strings[text_index_t{std::string(str), std::string(font)}] = ptr;
text_ptr_to_index[ptr] = index;
currently_rendered_strings.insert(ptr);
} }
auto index = added_texts.size();
added_texts.emplace_back(allocate_text());
auto ptr = added_texts.back().get();
ptr->setText(str, size);
text_ptr_to_text_index[ptr] = text_index_t{std::string(str), size, std::string(font)}; auto& vec = render_list[ptr];
rendered_strings[text_index_t{std::string(str), size, std::string(font)}] = ptr; vec.emplace_back(size);
text_ptr_to_index[ptr] = index; return vec.back();
currently_rendered_strings.insert(ptr);
return ptr;
} }
font_renderer_t::compiled_text_t& font_renderer_t::compiled_text_t::setText(std::string_view str, float size, std::string_view f) font_renderer_t::compiled_text_t& font_renderer_t::compiled_text_t::setText(std::string_view str, float size, std::string_view f)
@ -315,7 +339,6 @@ namespace blt::gfx
void font_renderer_t::compiled_text_t::draw() void font_renderer_t::compiled_text_t::draw()
{ {
font_texture_atlas* last_texture = nullptr; font_texture_atlas* last_texture = nullptr;
vao.bind();
for (const auto& render : renders) for (const auto& render : renders)
{ {
if (last_texture != render.texture) if (last_texture != render.texture)
@ -415,7 +438,7 @@ namespace blt::gfx
bool font_renderer_t::text_index_t::operator==(const font_renderer_t::text_index_t& rhs) const bool font_renderer_t::text_index_t::operator==(const font_renderer_t::text_index_t& rhs) const
{ {
return text == rhs.text && blt::f_equal(size, rhs.size) && font == rhs.font; return text == rhs.text && font == rhs.font;
} }
bool font_renderer_t::text_index_t::operator!=(const font_renderer_t::text_index_t& rhs) const bool font_renderer_t::text_index_t::operator!=(const font_renderer_t::text_index_t& rhs) const