diff --git a/libs/ui/include/psemek/ui/painter.hpp b/libs/ui/include/psemek/ui/painter.hpp index a25aef07..3faf2257 100644 --- a/libs/ui/include/psemek/ui/painter.hpp +++ b/libs/ui/include/psemek/ui/painter.hpp @@ -13,11 +13,18 @@ namespace psemek::ui namespace detail { + enum class color_mode + { + mix, + multiply, + }; + // Have to define this struct outside of ui::painter to workaround // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88165 struct image_options { gfx::color_rgba color{0, 0, 0, 0}; + color_mode mode = color_mode::mix; float rotation{0.f}; }; @@ -28,9 +35,9 @@ namespace psemek::ui virtual void draw_rect(geom::box const & rect, gfx::color_rgba const & color) = 0; virtual void draw_triangle(geom::triangle> const & tri, gfx::color_rgba const & color) = 0; + using color_mode = detail::color_mode; using image_options = detail::image_options; - 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_view_2d const & tex, image_options const & opts = image_options{}) = 0; virtual void begin_stencil() = 0; diff --git a/libs/ui/include/psemek/ui/painter_impl.hpp b/libs/ui/include/psemek/ui/painter_impl.hpp index 1b15deae..ed97c207 100644 --- a/libs/ui/include/psemek/ui/painter_impl.hpp +++ b/libs/ui/include/psemek/ui/painter_impl.hpp @@ -18,7 +18,6 @@ namespace psemek::ui void draw_rect(geom::box const & rect, gfx::color_rgba const & color) override; void draw_triangle(geom::triangle> const & tri, 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_view_2d const & tex, image_options const & opts) override; void begin_stencil() override; diff --git a/libs/ui/source/edit.cpp b/libs/ui/source/edit.cpp index ca85cf30..36a388c4 100644 --- a/libs/ui/source/edit.cpp +++ b/libs/ui/source/edit.cpp @@ -450,11 +450,11 @@ namespace psemek::ui { auto shoffset = offset + geom::cast(*st->text_shadow_offset); for (auto const & i : cached_state_->images) - p.draw_image(i.position + shoffset, {cached_state_->texture, i.texcoords}, {*st->shadow_color}); + p.draw_image(i.position + shoffset, {cached_state_->texture, i.texcoords}, {*st->shadow_color, painter::color_mode::multiply}); } for (auto const & i : cached_state_->images) - p.draw_image(i.position + offset, {cached_state_->texture, i.texcoords}, {*st->text_color}); + p.draw_image(i.position + offset, {cached_state_->texture, i.texcoords}, {*st->text_color, painter::color_mode::multiply}); p.end_stencil(); diff --git a/libs/ui/source/label.cpp b/libs/ui/source/label.cpp index e2d89473..e2c38d4d 100644 --- a/libs/ui/source/label.cpp +++ b/libs/ui/source/label.cpp @@ -111,12 +111,12 @@ namespace psemek::ui auto const offset = geom::cast(*st->text_shadow_offset); for (auto const & batch : cached_state_->batches) for (auto const & image : batch.images) - p.draw_image(image.position + offset, gfx::texture_view_2d{batch.texture, image.texcoords}, {*st->shadow_color}); + p.draw_image(image.position + offset, gfx::texture_view_2d{batch.texture, image.texcoords}, {*st->shadow_color, painter::color_mode::multiply}); } for (auto const & batch : cached_state_->batches) for (auto const & image : batch.images) - p.draw_image(image.position, gfx::texture_view_2d{batch.texture, image.texcoords}, {*st->text_color}); + p.draw_image(image.position, gfx::texture_view_2d{batch.texture, image.texcoords}, {*st->text_color, painter::color_mode::multiply}); } void label::on_state_changed() diff --git a/libs/ui/source/painter_impl.cpp b/libs/ui/source/painter_impl.cpp index 18df7499..d48642b5 100644 --- a/libs/ui/source/painter_impl.cpp +++ b/libs/ui/source/painter_impl.cpp @@ -44,45 +44,6 @@ void main() { out_color = color; } -)"; - - 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; -} -)"; - - 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); -} )"; char const textured_vs[] = @@ -108,7 +69,7 @@ void main() } )"; - char const textured_fs[] = + char const textured_mix_fs[] = R"(#version 330 uniform sampler2D u_texture; @@ -123,6 +84,23 @@ void main() vec4 tex_color = texture(u_texture, texcoord); out_color = vec4(mix(tex_color.rgb, color.rgb, color.a), tex_color.a); } +)"; + + char const textured_multiply_fs[] = +R"(#version 330 + +uniform sampler2D u_texture; + +in vec2 texcoord; +in vec4 color; + +out vec4 out_color; + +void main() +{ + vec4 tex_color = texture(u_texture, texcoord); + out_color = tex_color * color; +} )"; struct colored_vertex @@ -144,27 +122,6 @@ void main() return true; } - struct bitmap_text_vertex - { - geom::point position; - std::uint32_t depth; - gfx::color_rgba color; - geom::vector texcoords; - }; - static_assert(sizeof(bitmap_text_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_vertex { geom::point position; @@ -177,13 +134,14 @@ void main() struct textured_batch { gfx::texture_2d const * texture = nullptr; + painter::color_mode mode = painter::color_mode::mix; std::vector vertices{}; std::vector indices{}; }; bool operator == (textured_batch const & b1, textured_batch const & b2) { - return b1.texture == b2.texture; + return b1.texture == b2.texture && b1.mode == b2.mode; } struct stencil_batch @@ -212,10 +170,8 @@ 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::program textured_mix_program; + gfx::program textured_multiply_program; gfx::mesh textured_mesh; int stencil_level = 0; @@ -224,7 +180,7 @@ void main() geom::box draw_bbox; - std::vector> batches; + std::vector> batches; std::size_t max_batch_count = 0; @@ -246,17 +202,16 @@ 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} + , textured_mix_program{textured_vs, textured_mix_fs} + , textured_multiply_program{textured_vs, textured_multiply_fs} { - bitmap_text_program.bind(); - bitmap_text_program["u_atlas"] = 0; + textured_mix_program.bind(); + textured_mix_program["u_texture"] = 0; - textured_program.bind(); - textured_program["u_texture"] = 0; + textured_multiply_program.bind(); + textured_multiply_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>(); } @@ -304,47 +259,9 @@ void main() impl().draw_bbox |= tri[2]; } - void painter_impl::draw_glyph(font const & f, char32_t c, geom::box 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 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(bitmap_text_batch{&f.atlas()}); - - std::uint32_t const depth = impl().depth++; - std::uint32_t const base = batch.vertices.size(); - - auto round = [](geom::point p) - { - p[0] = std::round(p[0]); - p[1] = std::round(p[1]); - return p; - }; - - batch.vertices.push_back({round(rect.corner(0.f, 0.f)), depth, color, tc(0.f, 0.f)}); - batch.vertices.push_back({round(rect.corner(1.f, 0.f)), depth, color, tc(1.f, 0.f)}); - batch.vertices.push_back({round(rect.corner(0.f, 1.f)), depth, color, tc(0.f, 1.f)}); - batch.vertices.push_back({round(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}); - - impl().draw_bbox |= rect; - } - void painter_impl::draw_image(geom::box const & rect, gfx::texture_view_2d const & tex, image_options const & options) { - auto & batch = impl().batch(textured_batch{tex.texture}); + auto & batch = impl().batch(textured_batch{tex.texture, options.mode}); std::uint32_t const depth = impl().depth++; std::uint32_t const base = batch.vertices.size(); @@ -462,10 +379,10 @@ void main() { impl().colored_program.bind(); impl().colored_program["u_transform"] = transform; - impl().bitmap_text_program.bind(); - impl().bitmap_text_program["u_transform"] = transform; - impl().textured_program.bind(); - impl().textured_program["u_transform"] = transform; + impl().textured_mix_program.bind(); + impl().textured_mix_program["u_transform"] = transform; + impl().textured_multiply_program.bind(); + impl().textured_multiply_program["u_transform"] = transform; gl::ActiveTexture(gl::TEXTURE0); @@ -475,18 +392,11 @@ 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(); - impl().textured_program["u_texture_size"] = geom::cast(b.texture->size()); + gfx::program & program = (b.mode == ui::painter::color_mode::mix) ? impl().textured_mix_program : impl().textured_multiply_program; + program.bind(); + program["u_texture_size"] = geom::cast(b.texture->size()); b.texture->bind(); impl().textured_mesh.load(b.vertices, b.indices, gl::TRIANGLES); impl().textured_mesh.draw();