mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 20:37:35 +00:00
LibAccelGfx+LibWeb: Add text shadow support in GPU painter
This commit is contained in:
parent
b5f9c1d003
commit
5c0cd0f484
6 changed files with 133 additions and 4 deletions
|
@ -151,6 +151,12 @@ void delete_texture(Texture const& texture)
|
||||||
verify_no_error();
|
verify_no_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_uniform(Uniform const& uniform, int value)
|
||||||
|
{
|
||||||
|
glUniform1i(uniform.id, value);
|
||||||
|
verify_no_error();
|
||||||
|
}
|
||||||
|
|
||||||
void set_uniform(Uniform const& uniform, float value1, float value2)
|
void set_uniform(Uniform const& uniform, float value1, float value2)
|
||||||
{
|
{
|
||||||
glUniform2f(uniform.id, value1, value2);
|
glUniform2f(uniform.id, value1, value2);
|
||||||
|
|
|
@ -81,6 +81,7 @@ void bind_texture(Texture const&);
|
||||||
void upload_texture_data(Texture& texture, Gfx::Bitmap const& bitmap);
|
void upload_texture_data(Texture& texture, Gfx::Bitmap const& bitmap);
|
||||||
void delete_texture(Texture const&);
|
void delete_texture(Texture const&);
|
||||||
|
|
||||||
|
void set_uniform(Uniform const& uniform, int);
|
||||||
void set_uniform(Uniform const& uniform, float, float);
|
void set_uniform(Uniform const& uniform, float, float);
|
||||||
void set_uniform(Uniform const& uniform, float, float, float, float);
|
void set_uniform(Uniform const& uniform, float, float, float, float);
|
||||||
void set_vertex_attribute(VertexAttribute const& attribute, u32 offset, int number_of_components);
|
void set_vertex_attribute(VertexAttribute const& attribute, u32 offset, int number_of_components);
|
||||||
|
|
|
@ -135,6 +135,39 @@ void main() {
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
|
||||||
|
char const* blur_fragment_shader_source = R"(
|
||||||
|
#version 330 core
|
||||||
|
|
||||||
|
uniform vec2 uResolution;
|
||||||
|
uniform int uRadius;
|
||||||
|
uniform int uHorizontal;
|
||||||
|
uniform sampler2D uSampler;
|
||||||
|
|
||||||
|
in vec2 vTextureCoord;
|
||||||
|
out vec4 fragColor;
|
||||||
|
|
||||||
|
#define pow2(x) (x * x)
|
||||||
|
const float pi = atan(1.0) * 4.0;
|
||||||
|
float gaussian(vec2 i, float sigma) {
|
||||||
|
return 1.0 / (2.0 * pi * pow2(sigma)) * exp(-((pow2(i.x) + pow2(i.y)) / (2.0 * pow2(sigma))));
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 scale = vec2(1.0) / uResolution.xy;
|
||||||
|
float sigma = float(uRadius);
|
||||||
|
vec4 col = vec4(0.0);
|
||||||
|
float accum = 0.0;
|
||||||
|
float weight = 0.0;
|
||||||
|
for (int i = -uRadius; i <= uRadius; i++) {
|
||||||
|
vec2 offset = vec2(i * uHorizontal, i * (1 - uHorizontal));
|
||||||
|
weight = gaussian(offset, sigma);
|
||||||
|
col += texture(uSampler, vTextureCoord + scale * offset) * weight;
|
||||||
|
accum += weight;
|
||||||
|
}
|
||||||
|
fragColor = col / accum;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
HashMap<u32, GL::Texture> s_immutable_bitmap_texture_cache;
|
HashMap<u32, GL::Texture> s_immutable_bitmap_texture_cache;
|
||||||
|
|
||||||
NonnullOwnPtr<Painter> Painter::create()
|
NonnullOwnPtr<Painter> Painter::create()
|
||||||
|
@ -149,6 +182,7 @@ Painter::Painter(Context& context)
|
||||||
, m_rounded_rectangle_program(Program::create(Program::Name::RoundedRectangleProgram, vertex_shader_source, rect_with_rounded_corners_fragment_shader_source))
|
, m_rounded_rectangle_program(Program::create(Program::Name::RoundedRectangleProgram, vertex_shader_source, rect_with_rounded_corners_fragment_shader_source))
|
||||||
, m_blit_program(Program::create(Program::Name::BlitProgram, blit_vertex_shader_source, blit_fragment_shader_source))
|
, m_blit_program(Program::create(Program::Name::BlitProgram, blit_vertex_shader_source, blit_fragment_shader_source))
|
||||||
, m_linear_gradient_program(Program::create(Program::Name::LinearGradientProgram, linear_gradient_vertex_shader_source, linear_gradient_fragment_shader_source))
|
, m_linear_gradient_program(Program::create(Program::Name::LinearGradientProgram, linear_gradient_vertex_shader_source, linear_gradient_fragment_shader_source))
|
||||||
|
, m_blur_program(Program::create(Program::Name::BlurProgram, blit_vertex_shader_source, blur_fragment_shader_source))
|
||||||
{
|
{
|
||||||
m_state_stack.empend(State());
|
m_state_stack.empend(State());
|
||||||
}
|
}
|
||||||
|
@ -352,7 +386,7 @@ void Painter::draw_scaled_bitmap(Gfx::FloatRect const& dst_rect, Gfx::Bitmap con
|
||||||
GL::delete_texture(texture);
|
GL::delete_texture(texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Painter::draw_glyph_run(Vector<Gfx::DrawGlyphOrEmoji> const& glyph_run, Color const& color)
|
void Painter::draw_glyph_run(Span<Gfx::DrawGlyphOrEmoji const> glyph_run, Color const& color)
|
||||||
{
|
{
|
||||||
bind_target_canvas();
|
bind_target_canvas();
|
||||||
|
|
||||||
|
@ -667,6 +701,65 @@ void Painter::blit_scaled_texture(Gfx::FloatRect const& dst_rect, GL::Texture co
|
||||||
GL::delete_vertex_array(vao);
|
GL::delete_vertex_array(vao);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Painter::blit_blurred_texture(Gfx::FloatRect const& dst_rect, GL::Texture const& texture, Gfx::FloatRect const& src_rect, int radius, BlurDirection direction, ScalingMode scaling_mode)
|
||||||
|
{
|
||||||
|
bind_target_canvas();
|
||||||
|
|
||||||
|
m_blur_program.use();
|
||||||
|
|
||||||
|
auto dst_rect_in_clip_space = to_clip_space(transform().map(dst_rect));
|
||||||
|
auto src_rect_in_texture_space = to_texture_space(src_rect, *texture.size);
|
||||||
|
|
||||||
|
Vector<GLfloat> vertices;
|
||||||
|
vertices.ensure_capacity(16);
|
||||||
|
|
||||||
|
auto add_vertex = [&](auto const& p, auto const& s) {
|
||||||
|
vertices.append(p.x());
|
||||||
|
vertices.append(p.y());
|
||||||
|
vertices.append(s.x());
|
||||||
|
vertices.append(s.y());
|
||||||
|
};
|
||||||
|
|
||||||
|
add_vertex(dst_rect_in_clip_space.top_left(), src_rect_in_texture_space.top_left());
|
||||||
|
add_vertex(dst_rect_in_clip_space.bottom_left(), src_rect_in_texture_space.bottom_left());
|
||||||
|
add_vertex(dst_rect_in_clip_space.bottom_right(), src_rect_in_texture_space.bottom_right());
|
||||||
|
add_vertex(dst_rect_in_clip_space.top_right(), src_rect_in_texture_space.top_right());
|
||||||
|
|
||||||
|
auto vbo = GL::create_buffer();
|
||||||
|
GL::upload_to_buffer(vbo, vertices);
|
||||||
|
|
||||||
|
auto vao = GL::create_vertex_array();
|
||||||
|
GL::bind_vertex_array(vao);
|
||||||
|
GL::bind_buffer(vbo);
|
||||||
|
|
||||||
|
auto vertex_position_attribute = m_blur_program.get_attribute_location("aVertexPosition");
|
||||||
|
GL::set_vertex_attribute(vertex_position_attribute, 0, 4);
|
||||||
|
|
||||||
|
auto resolution_uniform = m_blur_program.get_uniform_location("uResolution");
|
||||||
|
GL::set_uniform(resolution_uniform, dst_rect.width(), dst_rect.height());
|
||||||
|
|
||||||
|
auto radius_uniform = m_blur_program.get_uniform_location("uRadius");
|
||||||
|
GL::set_uniform(radius_uniform, radius);
|
||||||
|
|
||||||
|
auto direction_uniform = m_blur_program.get_uniform_location("uHorizontal");
|
||||||
|
GL::set_uniform(direction_uniform, direction == BlurDirection::Horizontal ? 1 : 0);
|
||||||
|
|
||||||
|
GL::bind_texture(texture);
|
||||||
|
|
||||||
|
auto scaling_mode_gl = to_gl_scaling_mode(scaling_mode);
|
||||||
|
GL::set_texture_scale_mode(scaling_mode_gl);
|
||||||
|
GL::enable_blending(GL::BlendFactor::SrcAlpha, GL::BlendFactor::OneMinusSrcAlpha, GL::BlendFactor::One, GL::BlendFactor::One);
|
||||||
|
GL::draw_arrays(GL::DrawPrimitive::TriangleFan, 4);
|
||||||
|
|
||||||
|
GL::delete_buffer(vbo);
|
||||||
|
GL::delete_vertex_array(vao);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Painter::blit_blurred_canvas(Gfx::FloatRect const& dst_rect, Canvas const& canvas, int radius, BlurDirection direction, ScalingMode scaling_mode)
|
||||||
|
{
|
||||||
|
blit_blurred_texture(dst_rect, canvas.framebuffer().texture, { { 0, 0 }, canvas.size() }, radius, direction, scaling_mode);
|
||||||
|
}
|
||||||
|
|
||||||
void Painter::update_immutable_bitmap_texture_cache(HashMap<u32, Gfx::ImmutableBitmap const*>& immutable_bitmaps)
|
void Painter::update_immutable_bitmap_texture_cache(HashMap<u32, Gfx::ImmutableBitmap const*>& immutable_bitmaps)
|
||||||
{
|
{
|
||||||
for (auto immutable_bitmap_id : s_immutable_bitmap_texture_cache.keys()) {
|
for (auto immutable_bitmap_id : s_immutable_bitmap_texture_cache.keys()) {
|
||||||
|
|
|
@ -62,7 +62,7 @@ public:
|
||||||
void draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const&, Gfx::IntRect const& src_rect, ScalingMode = ScalingMode::NearestNeighbor);
|
void draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const&, Gfx::IntRect const& src_rect, ScalingMode = ScalingMode::NearestNeighbor);
|
||||||
void draw_scaled_immutable_bitmap(Gfx::FloatRect const& dst_rect, Gfx::ImmutableBitmap const&, Gfx::FloatRect const& src_rect, ScalingMode = ScalingMode::NearestNeighbor);
|
void draw_scaled_immutable_bitmap(Gfx::FloatRect const& dst_rect, Gfx::ImmutableBitmap const&, Gfx::FloatRect const& src_rect, ScalingMode = ScalingMode::NearestNeighbor);
|
||||||
|
|
||||||
void draw_glyph_run(Vector<Gfx::DrawGlyphOrEmoji> const& glyph_run, Color const& color);
|
void draw_glyph_run(Span<Gfx::DrawGlyphOrEmoji const> glyph_run, Color const& color);
|
||||||
|
|
||||||
void set_clip_rect(Gfx::IntRect);
|
void set_clip_rect(Gfx::IntRect);
|
||||||
void clear_clip_rect();
|
void clear_clip_rect();
|
||||||
|
@ -83,6 +83,12 @@ public:
|
||||||
void blit_canvas(Gfx::IntRect const& dst_rect, Canvas const&, float opacity = 1.0f, Optional<Gfx::AffineTransform> affine_transform = {});
|
void blit_canvas(Gfx::IntRect const& dst_rect, Canvas const&, float opacity = 1.0f, Optional<Gfx::AffineTransform> affine_transform = {});
|
||||||
void blit_canvas(Gfx::FloatRect const& dst_rect, Canvas const&, float opacity = 1.0f, Optional<Gfx::AffineTransform> affine_transform = {});
|
void blit_canvas(Gfx::FloatRect const& dst_rect, Canvas const&, float opacity = 1.0f, Optional<Gfx::AffineTransform> affine_transform = {});
|
||||||
|
|
||||||
|
enum class BlurDirection {
|
||||||
|
Horizontal,
|
||||||
|
Vertical,
|
||||||
|
};
|
||||||
|
void blit_blurred_canvas(Gfx::FloatRect const& dst_rect, Canvas const&, int radius, BlurDirection direction, ScalingMode = ScalingMode::NearestNeighbor);
|
||||||
|
|
||||||
void update_immutable_bitmap_texture_cache(HashMap<u32, Gfx::ImmutableBitmap const*>&);
|
void update_immutable_bitmap_texture_cache(HashMap<u32, Gfx::ImmutableBitmap const*>&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -97,6 +103,7 @@ private:
|
||||||
[[nodiscard]] State const& state() const { return m_state_stack.last(); }
|
[[nodiscard]] State const& state() const { return m_state_stack.last(); }
|
||||||
|
|
||||||
void blit_scaled_texture(Gfx::FloatRect const& dst_rect, GL::Texture const&, Gfx::FloatRect const& src_rect, ScalingMode, float opacity = 1.0f, Optional<Gfx::AffineTransform> affine_transform = {});
|
void blit_scaled_texture(Gfx::FloatRect const& dst_rect, GL::Texture const&, Gfx::FloatRect const& src_rect, ScalingMode, float opacity = 1.0f, Optional<Gfx::AffineTransform> affine_transform = {});
|
||||||
|
void blit_blurred_texture(Gfx::FloatRect const& dst_rect, GL::Texture const&, Gfx::FloatRect const& src_rect, int radius, BlurDirection direction, ScalingMode = ScalingMode::NearestNeighbor);
|
||||||
void bind_target_canvas();
|
void bind_target_canvas();
|
||||||
|
|
||||||
[[nodiscard]] Gfx::FloatRect to_clip_space(Gfx::FloatRect const& screen_rect) const;
|
[[nodiscard]] Gfx::FloatRect to_clip_space(Gfx::FloatRect const& screen_rect) const;
|
||||||
|
@ -109,6 +116,7 @@ private:
|
||||||
Program m_rounded_rectangle_program;
|
Program m_rounded_rectangle_program;
|
||||||
Program m_blit_program;
|
Program m_blit_program;
|
||||||
Program m_linear_gradient_program;
|
Program m_linear_gradient_program;
|
||||||
|
Program m_blur_program;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ public:
|
||||||
RoundedRectangleProgram,
|
RoundedRectangleProgram,
|
||||||
BlitProgram,
|
BlitProgram,
|
||||||
LinearGradientProgram,
|
LinearGradientProgram,
|
||||||
|
BlurProgram,
|
||||||
|
|
||||||
ProgramCount,
|
ProgramCount,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -165,9 +165,28 @@ CommandResult PaintingCommandExecutorGPU::paint_inner_box_shadow(PaintOuterBoxSh
|
||||||
return CommandResult::Continue;
|
return CommandResult::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandResult PaintingCommandExecutorGPU::paint_text_shadow(int, Gfx::IntRect const&, Gfx::IntRect const&, Span<Gfx::DrawGlyphOrEmoji const>, Color const&, int, Gfx::IntPoint const&)
|
CommandResult PaintingCommandExecutorGPU::paint_text_shadow(int blur_radius, Gfx::IntRect const& shadow_bounding_rect, Gfx::IntRect const& text_rect, Span<Gfx::DrawGlyphOrEmoji const> glyph_run, Color const& color, int fragment_baseline, Gfx::IntPoint const& draw_location)
|
||||||
{
|
{
|
||||||
// FIXME
|
auto text_shadow_canvas = AccelGfx::Canvas::create(shadow_bounding_rect.size());
|
||||||
|
auto text_shadow_painter = AccelGfx::Painter::create();
|
||||||
|
text_shadow_painter->set_target_canvas(text_shadow_canvas);
|
||||||
|
text_shadow_painter->clear(color.with_alpha(0));
|
||||||
|
|
||||||
|
Gfx::FloatRect const shadow_location { draw_location, shadow_bounding_rect.size() };
|
||||||
|
Gfx::IntPoint const baseline_start(text_rect.x(), text_rect.y() + fragment_baseline);
|
||||||
|
text_shadow_painter->translate(baseline_start.to_type<float>());
|
||||||
|
text_shadow_painter->draw_glyph_run(glyph_run, color);
|
||||||
|
if (blur_radius == 0) {
|
||||||
|
painter().blit_canvas(shadow_location, *text_shadow_canvas);
|
||||||
|
return CommandResult::Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto horizontal_blur_canvas = AccelGfx::Canvas::create(shadow_bounding_rect.size());
|
||||||
|
auto horizontal_blur_painter = AccelGfx::Painter::create();
|
||||||
|
horizontal_blur_painter->set_target_canvas(horizontal_blur_canvas);
|
||||||
|
horizontal_blur_painter->clear(color.with_alpha(0));
|
||||||
|
horizontal_blur_painter->blit_blurred_canvas(shadow_bounding_rect.to_type<float>(), *text_shadow_canvas, blur_radius, AccelGfx::Painter::BlurDirection::Horizontal);
|
||||||
|
painter().blit_blurred_canvas(shadow_location, *horizontal_blur_canvas, blur_radius, AccelGfx::Painter::BlurDirection::Vertical);
|
||||||
return CommandResult::Continue;
|
return CommandResult::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue