From dbc429eaa7410167d6e86af711911800e3b23d4b Mon Sep 17 00:00:00 2001 From: lisyarus Date: Sun, 27 Sep 2020 19:14:50 +0300 Subject: [PATCH] Support 3D text in painter --- libs/gfx/include/psemek/gfx/painter.hpp | 1 + libs/gfx/source/painter.cpp | 143 ++++++++++++------------ 2 files changed, 75 insertions(+), 69 deletions(-) diff --git a/libs/gfx/include/psemek/gfx/painter.hpp b/libs/gfx/include/psemek/gfx/painter.hpp index 5c8180ab..02c86d22 100644 --- a/libs/gfx/include/psemek/gfx/painter.hpp +++ b/libs/gfx/include/psemek/gfx/painter.hpp @@ -60,6 +60,7 @@ namespace psemek::gfx // 3D void axes(geom::point const & p, float length, float width); void sphere(geom::point const & p, float radius, color const & c, int quality = 6); + void text3d(geom::point const & p, std::string_view str, text_options const & opts, geom::matrix const & transform); // Should be called on each frame void render(geom::matrix const & transform); diff --git a/libs/gfx/source/painter.cpp b/libs/gfx/source/painter.cpp index 9701c431..350593c3 100644 --- a/libs/gfx/source/painter.cpp +++ b/libs/gfx/source/painter.cpp @@ -87,7 +87,7 @@ namespace psemek::gfx struct text_vertex { - geom::point position; + geom::point position; color_rgba color; geom::point texcoord; }; @@ -108,7 +108,7 @@ namespace psemek::gfx impl() { mesh.setup, gfx::normalized>(); - text_mesh.setup, gfx::normalized, geom::point>(); + text_mesh.setup, gfx::normalized, geom::point>(); util::memory_istream font_data(resource::font_9x12); font_texture.load(gfx::read_pbm(font_data)); @@ -228,73 +228,7 @@ namespace psemek::gfx void painter::text(geom::point const & p, std::string_view str, text_options const & opts) { - auto const size = text_size(str, opts.f, opts.scale); - - auto pen = p; - - switch (opts.x) - { - case x_align::left: - break; - case x_align::center: - pen[0] -= size[0] / 2.f; - break; - case x_align::right: - pen[0] -= size[0]; - break; - default: - throw std::runtime_error("Unknown x alignment"); - } - - switch (opts.y) - { - case y_align::top: - break; - case y_align::center: - pen[1] -= size[1] / 2.f; - break; - case y_align::bottom: - pen[1] -= size[1]; - break; - default: - throw std::runtime_error("Unknown y alignment"); - } - - geom::vector const sx = {9.f * opts.scale, 0.f}; - geom::vector const sy = {0.f, 12.f * opts.scale}; - - auto to_texcoord = [](int tx, int ty, int ix, int iy) - { - return geom::point{ tx * 11 + (ix == 0 ? 1 : 10), ty * 14 + (iy == 0 ? 1 : 13) }; - }; - - for (char c : str) - { - // Guard against unsigned char -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wtype-limits" - if ((c < 32) || (c >= 128)) c = '?'; -#pragma GCC diagnostic pop - - int ty = (c - 32) / 16; - int tx = (c - 32) % 16; - - std::uint32_t const base = impl().text_vertices.size(); - - impl().text_vertices.push_back({pen, opts.c, to_texcoord(tx, ty, 0, 0)}); - impl().text_vertices.push_back({pen + sx, opts.c, to_texcoord(tx, ty, 1, 0)}); - impl().text_vertices.push_back({pen + sy, opts.c, to_texcoord(tx, ty, 0, 1)}); - impl().text_vertices.push_back({pen + sx + sy, opts.c, to_texcoord(tx, ty, 1, 1)}); - - impl().text_indices.push_back(base + 0); - impl().text_indices.push_back(base + 1); - impl().text_indices.push_back(base + 3); - impl().text_indices.push_back(base + 0); - impl().text_indices.push_back(base + 3); - impl().text_indices.push_back(base + 2); - - pen += sx; - } + text3d(geom::point{p[0], p[1], 0.f}, str, opts, geom::matrix::identity()); } void painter::axes(geom::point const & p, float length, float width) @@ -422,6 +356,77 @@ namespace psemek::gfx } } + void painter::text3d(geom::point const & p, std::string_view str, text_options const & opts, geom::matrix const & t) + { + auto const size = text_size(str, opts.f, opts.scale); + + geom::vector pen { 0.f, 0.f, 0.f }; + + switch (opts.x) + { + case x_align::left: + break; + case x_align::center: + pen[0] -= size[0] / 2.f; + break; + case x_align::right: + pen[0] -= size[0]; + break; + default: + throw std::runtime_error("Unknown x alignment"); + } + + switch (opts.y) + { + case y_align::top: + break; + case y_align::center: + pen[1] -= size[1] / 2.f; + break; + case y_align::bottom: + pen[1] -= size[1]; + break; + default: + throw std::runtime_error("Unknown y alignment"); + } + + geom::vector const sx = {9.f * opts.scale, 0.f, 0.f}; + geom::vector const sy = {0.f, 12.f * opts.scale, 0.f}; + + auto to_texcoord = [](int tx, int ty, int ix, int iy) + { + return geom::point{ tx * 11 + (ix == 0 ? 1 : 10), ty * 14 + (iy == 0 ? 1 : 13) }; + }; + + for (char c : str) + { + // Guard against unsigned char +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" + if ((c < 32) || (c >= 128)) c = '?'; +#pragma GCC diagnostic pop + + int ty = (c - 32) / 16; + int tx = (c - 32) % 16; + + std::uint32_t const base = impl().text_vertices.size(); + + impl().text_vertices.push_back({p + t * pen, opts.c, to_texcoord(tx, ty, 0, 0)}); + impl().text_vertices.push_back({p + t * (pen + sx), opts.c, to_texcoord(tx, ty, 1, 0)}); + impl().text_vertices.push_back({p + t * (pen + sy), opts.c, to_texcoord(tx, ty, 0, 1)}); + impl().text_vertices.push_back({p + t * (pen + sx + sy), opts.c, to_texcoord(tx, ty, 1, 1)}); + + impl().text_indices.push_back(base + 0); + impl().text_indices.push_back(base + 1); + impl().text_indices.push_back(base + 3); + impl().text_indices.push_back(base + 0); + impl().text_indices.push_back(base + 3); + impl().text_indices.push_back(base + 2); + + pen += sx; + } + } + void painter::render(geom::matrix const & transform) { impl().mesh.load(impl().vertices, impl().indices, gl::TRIANGLES, gl::STREAM_DRAW);