Implement glyph rendering in painter
This commit is contained in:
parent
867deddd87
commit
b9dd6c78a3
3 changed files with 165 additions and 35 deletions
|
|
@ -10,6 +10,7 @@ namespace psemek::ui
|
|||
struct painter
|
||||
{
|
||||
virtual void draw_rect(geom::box<float, 2> const & rect, gfx::color_rgba const & color) = 0;
|
||||
virtual void draw_glyph(font const & f, char32_t c, geom::box<float, 2> const & rect, gfx::color_rgba const & color) = 0;
|
||||
|
||||
virtual ~painter() {}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ namespace psemek::ui
|
|||
~painter_impl();
|
||||
|
||||
void draw_rect(geom::box<float, 2> const & rect, gfx::color_rgba const & color) override;
|
||||
void draw_glyph(font const & f, char32_t c, geom::box<float, 2> const & rect, gfx::color_rgba const & color) override;
|
||||
|
||||
void render(geom::matrix<float, 4, 4> const & transform);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
#include <psemek/ui/painter_impl.hpp>
|
||||
|
||||
#include <psemek/gfx/program.hpp>
|
||||
#include <psemek/gfx/array.hpp>
|
||||
#include <psemek/gfx/buffer.hpp>
|
||||
#include <psemek/gfx/mesh.hpp>
|
||||
|
||||
#include <psemek/util/overload.hpp>
|
||||
|
||||
#include <variant>
|
||||
|
||||
namespace psemek::ui
|
||||
{
|
||||
|
|
@ -13,7 +16,7 @@ R"(#version 330
|
|||
uniform mat4 u_transform;
|
||||
|
||||
layout (location = 0) in vec2 in_position;
|
||||
layout (location = 1) in uint in_depth;
|
||||
layout (location = 1) in float in_depth;
|
||||
layout (location = 2) in vec4 in_color;
|
||||
|
||||
out vec4 color;
|
||||
|
|
@ -38,6 +41,46 @@ void main()
|
|||
}
|
||||
)";
|
||||
|
||||
static char const textured_vs[] =
|
||||
R"(#version 330
|
||||
|
||||
uniform mat4 u_transform;
|
||||
|
||||
uniform vec2 u_texture_size;
|
||||
|
||||
layout (location = 0) in vec2 in_position;
|
||||
layout (location = 1) in float in_depth;
|
||||
layout (location = 2) in vec4 in_color;
|
||||
layout (location = 3) in vec2 in_texcoord;
|
||||
|
||||
out vec4 color;
|
||||
out vec2 texcoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = u_transform * vec4(in_position, 1.0 - float(in_depth) / 16777216.0 * 2.0, 1.0);
|
||||
color = in_color;
|
||||
texcoord = in_texcoord / u_texture_size;
|
||||
}
|
||||
)";
|
||||
|
||||
static char const textured_fs[] =
|
||||
R"(#version 330
|
||||
|
||||
uniform sampler2D u_texture;
|
||||
|
||||
in vec2 texcoord;
|
||||
in vec4 color;
|
||||
|
||||
out vec4 out_color;
|
||||
|
||||
void main()
|
||||
{
|
||||
out_color = texture(u_texture, texcoord) * color;
|
||||
}
|
||||
)";
|
||||
|
||||
|
||||
struct colored_vertex
|
||||
{
|
||||
geom::point<float, 2> position;
|
||||
|
|
@ -46,33 +89,75 @@ void main()
|
|||
};
|
||||
static_assert(sizeof(colored_vertex) == 16);
|
||||
|
||||
struct colored_batch
|
||||
{
|
||||
std::vector<colored_vertex> vertices;
|
||||
std::vector<std::uint32_t> indices;
|
||||
};
|
||||
|
||||
bool operator == (colored_batch const &, colored_batch const &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
struct textured_vertex
|
||||
{
|
||||
geom::point<float, 2> position;
|
||||
std::uint32_t depth;
|
||||
gfx::color_rgba color;
|
||||
geom::vector<std::uint16_t, 2> texcoords;
|
||||
};
|
||||
static_assert(sizeof(textured_vertex) == 20);
|
||||
|
||||
struct textured_batch
|
||||
{
|
||||
gfx::texture_2d const * texture = nullptr;
|
||||
std::vector<textured_vertex> vertices{};
|
||||
std::vector<std::uint32_t> indices{};
|
||||
};
|
||||
|
||||
bool operator == (textured_batch const & b1, textured_batch const & b2)
|
||||
{
|
||||
return b1.texture == b2.texture;
|
||||
}
|
||||
|
||||
struct painter_impl::impl
|
||||
{
|
||||
std::uint32_t depth = 0;
|
||||
|
||||
gfx::program colored_program;
|
||||
gfx::array colored_vao;
|
||||
gfx::buffer colored_vbo;
|
||||
gfx::buffer colored_ebo;
|
||||
gfx::mesh colored_mesh;
|
||||
|
||||
std::vector<colored_vertex> colored_vertices;
|
||||
std::vector<std::uint32_t> colored_indices;
|
||||
gfx::program textured_program;
|
||||
gfx::mesh textured_mesh;
|
||||
|
||||
std::vector<std::variant<colored_batch, textured_batch>> batches;
|
||||
|
||||
template <typename Batch>
|
||||
Batch & batch(Batch && n)
|
||||
{
|
||||
if (!batches.empty())
|
||||
{
|
||||
auto b = std::get_if<Batch>(&batches.back());
|
||||
if (b && *b == n) return *b;
|
||||
}
|
||||
|
||||
batches.push_back(std::move(n));
|
||||
return std::get<Batch>(batches.back());
|
||||
}
|
||||
|
||||
impl();
|
||||
};
|
||||
|
||||
painter_impl::impl::impl()
|
||||
: colored_program{colored_vs, colored_fs}
|
||||
, textured_program{textured_vs, textured_fs}
|
||||
{
|
||||
colored_vao.bind();
|
||||
colored_vbo.bind();
|
||||
gl::EnableVertexAttribArray(0);
|
||||
gl::VertexAttribPointer(0, 2, gl::FLOAT, gl::FALSE, sizeof(colored_vertex), reinterpret_cast<void const *>(0));
|
||||
gl::EnableVertexAttribArray(1);
|
||||
gl::VertexAttribIPointer(1, 1, gl::UNSIGNED_INT, sizeof(colored_vertex), reinterpret_cast<void const *>(8));
|
||||
gl::EnableVertexAttribArray(2);
|
||||
gl::VertexAttribPointer(2, 4, gl::UNSIGNED_BYTE, gl::TRUE, sizeof(colored_vertex), reinterpret_cast<void const *>(12));
|
||||
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, colored_ebo.id());
|
||||
textured_program.bind();
|
||||
textured_program["u_texture"] = 0;
|
||||
|
||||
colored_mesh.setup<geom::point<float, 2>, std::uint32_t, gfx::normalized<gfx::color_rgba>>();
|
||||
textured_mesh.setup<geom::point<float, 2>, std::uint32_t, gfx::normalized<gfx::color_rgba>, geom::vector<std::uint16_t, 2>>();
|
||||
}
|
||||
|
||||
painter_impl::painter_impl()
|
||||
|
|
@ -83,33 +168,76 @@ void main()
|
|||
|
||||
void painter_impl::draw_rect(geom::box<float, 2> const & rect, gfx::color_rgba const & color)
|
||||
{
|
||||
auto & batch = impl().batch<colored_batch>({});
|
||||
|
||||
std::uint32_t const depth = impl().depth++;
|
||||
std::uint32_t const base = impl().colored_vertices.size();
|
||||
std::uint32_t const base = batch.vertices.size();
|
||||
|
||||
impl().colored_vertices.push_back({rect.corner(0.f, 0.f), depth, color});
|
||||
impl().colored_vertices.push_back({rect.corner(1.f, 0.f), depth, color});
|
||||
impl().colored_vertices.push_back({rect.corner(0.f, 1.f), depth, color});
|
||||
impl().colored_vertices.push_back({rect.corner(1.f, 1.f), depth, color});
|
||||
batch.vertices.push_back({rect.corner(0.f, 0.f), depth, color});
|
||||
batch.vertices.push_back({rect.corner(1.f, 0.f), depth, color});
|
||||
batch.vertices.push_back({rect.corner(0.f, 1.f), depth, color});
|
||||
batch.vertices.push_back({rect.corner(1.f, 1.f), depth, color});
|
||||
|
||||
impl().colored_indices.insert(impl().colored_indices.end(), {base + 0, base + 1, base + 2, base + 2, base + 1, base + 3});
|
||||
batch.indices.insert(batch.indices.end(), {base + 0, base + 1, base + 2, base + 2, base + 1, base + 3});
|
||||
}
|
||||
|
||||
void painter_impl::draw_glyph(font const & f, char32_t c, geom::box<float, 2> const & rect, gfx::color_rgba const & color)
|
||||
{
|
||||
auto tbox = f.texcoords(c);
|
||||
if (!tbox) return;
|
||||
|
||||
auto size = f.atlas().size();
|
||||
|
||||
auto const tc = [&](float x, float y)
|
||||
{
|
||||
auto t = tbox->corner(x, y);
|
||||
geom::vector<std::uint16_t, 2> r;
|
||||
r[0] = geom::clamp(t[0], {0, size[0]});
|
||||
r[1] = geom::clamp(t[1], {0, size[1]});
|
||||
return r;
|
||||
};
|
||||
|
||||
auto & batch = impl().batch<textured_batch>(textured_batch{&f.atlas()});
|
||||
|
||||
std::uint32_t const depth = impl().depth++;
|
||||
std::uint32_t const base = batch.vertices.size();
|
||||
|
||||
batch.vertices.push_back({rect.corner(0.f, 0.f), depth, color, tc(0.f, 0.f)});
|
||||
batch.vertices.push_back({rect.corner(1.f, 0.f), depth, color, tc(1.f, 0.f)});
|
||||
batch.vertices.push_back({rect.corner(0.f, 1.f), depth, color, tc(0.f, 1.f)});
|
||||
batch.vertices.push_back({rect.corner(1.f, 1.f), depth, color, tc(1.f, 1.f)});
|
||||
|
||||
batch.indices.insert(batch.indices.end(), {base + 0, base + 1, base + 2, base + 2, base + 1, base + 3});
|
||||
}
|
||||
|
||||
void painter_impl::render(geom::matrix<float, 4, 4> const & transform)
|
||||
{
|
||||
impl().colored_vbo.load(impl().colored_vertices);
|
||||
impl().colored_ebo.load(impl().colored_indices);
|
||||
|
||||
int const colored_count = impl().colored_indices.size();
|
||||
|
||||
impl().colored_vertices.clear();
|
||||
impl().colored_indices.clear();
|
||||
|
||||
impl().depth = 0;
|
||||
|
||||
impl().colored_program.bind();
|
||||
impl().colored_program["u_transform"] = transform;
|
||||
impl().colored_vao.bind();
|
||||
gl::DrawElements(gl::TRIANGLES, colored_count, gl::UNSIGNED_INT, nullptr);
|
||||
impl().textured_program.bind();
|
||||
impl().textured_program["u_transform"] = transform;
|
||||
|
||||
gl::ActiveTexture(gl::TEXTURE0);
|
||||
|
||||
auto batch_visitor = util::overload([&](colored_batch const & b){
|
||||
impl().colored_program.bind();
|
||||
impl().colored_mesh.load(b.vertices, b.indices, gl::TRIANGLES);
|
||||
impl().colored_mesh.draw();
|
||||
},
|
||||
[&](textured_batch const & b){
|
||||
if (!b.texture) return;
|
||||
impl().textured_program.bind();
|
||||
impl().textured_program["u_texture_size"] = geom::cast<float>(b.texture->size());
|
||||
b.texture->bind();
|
||||
impl().textured_mesh.load(b.vertices, b.indices, gl::TRIANGLES);
|
||||
impl().textured_mesh.draw();
|
||||
});
|
||||
|
||||
for (auto const & b : impl().batches)
|
||||
std::visit(batch_visitor, b);
|
||||
|
||||
impl().depth = 0;
|
||||
impl().batches.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue