Support 3D text in painter

This commit is contained in:
Nikita Lisitsa 2020-09-27 19:14:50 +03:00
parent 90ece36fd5
commit dbc429eaa7
2 changed files with 75 additions and 69 deletions

View file

@ -60,6 +60,7 @@ namespace psemek::gfx
// 3D
void axes(geom::point<float, 3> const & p, float length, float width);
void sphere(geom::point<float, 3> const & p, float radius, color const & c, int quality = 6);
void text3d(geom::point<float, 3> const & p, std::string_view str, text_options const & opts, geom::matrix<float, 3, 3> const & transform);
// Should be called on each frame
void render(geom::matrix<float, 4, 4> const & transform);

View file

@ -87,7 +87,7 @@ namespace psemek::gfx
struct text_vertex
{
geom::point<float, 2> position;
geom::point<float, 3> position;
color_rgba color;
geom::point<std::uint16_t, 2> texcoord;
};
@ -108,7 +108,7 @@ namespace psemek::gfx
impl()
{
mesh.setup<geom::vector<float, 3>, gfx::normalized<color_rgba>>();
text_mesh.setup<geom::point<float, 2>, gfx::normalized<color_rgba>, geom::point<std::uint16_t, 2>>();
text_mesh.setup<geom::point<float, 3>, gfx::normalized<color_rgba>, geom::point<std::uint16_t, 2>>();
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<float, 2> 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<float, 2> const sx = {9.f * opts.scale, 0.f};
geom::vector<float, 2> const sy = {0.f, 12.f * opts.scale};
auto to_texcoord = [](int tx, int ty, int ix, int iy)
{
return geom::point<std::uint16_t, 2>{ 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<float, 3, 3>::identity());
}
void painter::axes(geom::point<float, 3> const & p, float length, float width)
@ -422,6 +356,77 @@ namespace psemek::gfx
}
}
void painter::text3d(geom::point<float, 3> const & p, std::string_view str, text_options const & opts, geom::matrix<float, 3, 3> const & t)
{
auto const size = text_size(str, opts.f, opts.scale);
geom::vector<float, 3> 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<float, 3> const sx = {9.f * opts.scale, 0.f, 0.f};
geom::vector<float, 3> const sy = {0.f, 12.f * opts.scale, 0.f};
auto to_texcoord = [](int tx, int ty, int ix, int iy)
{
return geom::point<std::uint16_t, 2>{ 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<float, 4, 4> const & transform)
{
impl().mesh.load(impl().vertices, impl().indices, gl::TRIANGLES, gl::STREAM_DRAW);