diff --git a/libs/ui/include/psemek/ui/painter.hpp b/libs/ui/include/psemek/ui/painter.hpp index e857ae96..9cd04ddf 100644 --- a/libs/ui/include/psemek/ui/painter.hpp +++ b/libs/ui/include/psemek/ui/painter.hpp @@ -2,6 +2,7 @@ #include #include +#include #include namespace psemek::ui @@ -11,6 +12,7 @@ namespace psemek::ui { virtual void draw_rect(geom::box const & rect, gfx::color_rgba const & color) = 0; virtual void draw_glyph(font const & f, char32_t c, geom::box const & rect, gfx::color_rgba const & color) = 0; + virtual void draw_image(geom::box const & rect, gfx::texture_2d const & tex, gfx::color_rgba const & color = {0, 0, 0, 0}) = 0; virtual ~painter() {} }; diff --git a/libs/ui/include/psemek/ui/painter_impl.hpp b/libs/ui/include/psemek/ui/painter_impl.hpp index e35f3d4a..0293dff3 100644 --- a/libs/ui/include/psemek/ui/painter_impl.hpp +++ b/libs/ui/include/psemek/ui/painter_impl.hpp @@ -17,6 +17,7 @@ namespace psemek::ui void draw_rect(geom::box const & rect, gfx::color_rgba const & color) override; void draw_glyph(font const & f, char32_t c, geom::box const & rect, gfx::color_rgba const & color) override; + void draw_image(geom::box const & rect, gfx::texture_2d const & tex, gfx::color_rgba const & color) override; void render(geom::matrix const & transform); diff --git a/libs/ui/source/painter_impl.cpp b/libs/ui/source/painter_impl.cpp index 28d23333..cfaeace0 100644 --- a/libs/ui/source/painter_impl.cpp +++ b/libs/ui/source/painter_impl.cpp @@ -39,6 +39,45 @@ void main() { out_color = color; } +)"; + + static char const bitmap_text_vs[] = +R"(#version 330 + +uniform mat4 u_transform; + +uniform vec2 u_atlas_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_atlas_size; +} +)"; + + static char const bitmap_text_fs[] = +R"(#version 330 + +uniform sampler2D u_atlas; + +in vec2 texcoord; +in vec4 color; + +out vec4 out_color; + +void main() +{ + out_color = vec4(color.rgb, texture(u_atlas, texcoord) * color.a); +} )"; static char const textured_vs[] = @@ -76,7 +115,7 @@ out vec4 out_color; void main() { - out_color = texture(u_texture, texcoord) * color; + out_color = mix(texture(u_texture, texcoord), color, color.a); } )"; @@ -109,6 +148,18 @@ void main() }; static_assert(sizeof(textured_vertex) == 20); + struct bitmap_text_batch + { + gfx::texture_2d const * atlas = nullptr; + std::vector vertices{}; + std::vector indices{}; + }; + + bool operator == (bitmap_text_batch const & b1, bitmap_text_batch const & b2) + { + return b1.atlas == b2.atlas; + } + struct textured_batch { gfx::texture_2d const * texture = nullptr; @@ -128,10 +179,13 @@ void main() gfx::program colored_program; gfx::mesh colored_mesh; + gfx::program bitmap_text_program; + gfx::mesh bitmap_text_mesh; + gfx::program textured_program; gfx::mesh textured_mesh; - std::vector> batches; + std::vector> batches; template Batch & batch(Batch && n) @@ -151,12 +205,17 @@ void main() painter_impl::impl::impl() : colored_program{colored_vs, colored_fs} + , bitmap_text_program{bitmap_text_vs, bitmap_text_fs} , textured_program{textured_vs, textured_fs} { + bitmap_text_program.bind(); + bitmap_text_program["u_atlas"] = 0; + textured_program.bind(); textured_program["u_texture"] = 0; colored_mesh.setup, std::uint32_t, gfx::normalized>(); + bitmap_text_mesh.setup, std::uint32_t, gfx::normalized, geom::vector>(); textured_mesh.setup, std::uint32_t, gfx::normalized, geom::vector>(); } @@ -197,7 +256,7 @@ void main() return r; }; - auto & batch = impl().batch(textured_batch{&f.atlas()}); + auto & batch = impl().batch(bitmap_text_batch{&f.atlas()}); std::uint32_t const depth = impl().depth++; std::uint32_t const base = batch.vertices.size(); @@ -210,6 +269,23 @@ void main() batch.indices.insert(batch.indices.end(), {base + 0, base + 1, base + 2, base + 2, base + 1, base + 3}); } + void painter_impl::draw_image(geom::box const & rect, gfx::texture_2d const & tex, gfx::color_rgba const & color) + { + auto & batch = impl().batch(textured_batch{&tex}); + + std::uint32_t const depth = impl().depth++; + std::uint32_t const base = batch.vertices.size(); + + auto const size = tex.size(); + + batch.vertices.push_back({rect.corner(0.f, 0.f), depth, color, {0, 0}}); + batch.vertices.push_back({rect.corner(1.f, 0.f), depth, color, {size[0], 0}}); + batch.vertices.push_back({rect.corner(0.f, 1.f), depth, color, {0, size[1]}}); + batch.vertices.push_back({rect.corner(1.f, 1.f), depth, color, {size[0], size[1]}}); + + batch.indices.insert(batch.indices.end(), {base + 0, base + 1, base + 2, base + 2, base + 1, base + 3}); + } + void painter_impl::render(geom::matrix const & transform) { impl().colored_program.bind(); @@ -224,6 +300,14 @@ void main() impl().colored_mesh.load(b.vertices, b.indices, gl::TRIANGLES); impl().colored_mesh.draw(); }, + [&](bitmap_text_batch const & b){ + if (!b.atlas) return; + impl().bitmap_text_program.bind(); + impl().bitmap_text_program["u_atlas_size"] = geom::cast(b.atlas->size()); + b.atlas->bind(); + impl().bitmap_text_mesh.load(b.vertices, b.indices, gl::TRIANGLES); + impl().bitmap_text_mesh.draw(); + }, [&](textured_batch const & b){ if (!b.texture) return; impl().textured_program.bind();