mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-04 13:30:31 +00:00
LibAccelGfx+LibWeb: Add basic support for linear gradients painting
Linear gradient painting is implemented in the following way: 1. The rectangle is divided into segments where each segment represents a simple linear gradient between an adjacent pair of stops. 2. Each quad is filled separately using a fragment shader that interpolates between two colors. For now `angle` and `repeat_length` parameters are ignored.
This commit is contained in:
parent
61a2e59d87
commit
f6a9f613c7
Notes:
sideshowbarker
2024-07-17 02:22:23 +09:00
Author: https://github.com/kalenikaliaksandr Commit: https://github.com/SerenityOS/serenity/commit/f6a9f613c7 Pull-request: https://github.com/SerenityOS/serenity/pull/21950
3 changed files with 119 additions and 2 deletions
|
@ -79,6 +79,26 @@ void main() {
|
|||
}
|
||||
)";
|
||||
|
||||
char const* linear_gradient_vertex_shader_source = R"(
|
||||
#version 330 core
|
||||
layout (location = 0) in vec2 aVertexPosition;
|
||||
layout (location = 1) in vec4 aColor;
|
||||
out vec4 vColor;
|
||||
void main() {
|
||||
gl_Position = vec4(aVertexPosition, 0.0, 1.0);
|
||||
vColor = aColor;
|
||||
}
|
||||
)";
|
||||
|
||||
char const* linear_gradient_fragment_shader_source = R"(
|
||||
#version 330 core
|
||||
out vec4 FragColor;
|
||||
in vec4 vColor;
|
||||
void main() {
|
||||
FragColor = vec4(vColor);
|
||||
}
|
||||
)";
|
||||
|
||||
OwnPtr<Painter> Painter::create()
|
||||
{
|
||||
auto& context = Context::the();
|
||||
|
@ -89,6 +109,7 @@ Painter::Painter(Context& context)
|
|||
: m_context(context)
|
||||
, m_rectangle_program(Program::create(vertex_shader_source, solid_color_fragment_shader_source))
|
||||
, m_blit_program(Program::create(blit_vertex_shader_source, blit_fragment_shader_source))
|
||||
, m_linear_gradient_program(Program::create(linear_gradient_vertex_shader_source, linear_gradient_fragment_shader_source))
|
||||
, m_glyphs_texture(GL::create_texture())
|
||||
{
|
||||
m_state_stack.empend(State());
|
||||
|
@ -406,6 +427,97 @@ void Painter::draw_glyph_run(Vector<Gfx::DrawGlyphOrEmoji> const& glyph_run, Col
|
|||
GL::delete_vertex_array(vao);
|
||||
}
|
||||
|
||||
void Painter::fill_rect_with_linear_gradient(Gfx::IntRect const& rect, ReadonlySpan<Gfx::ColorStop> stops, float angle, Optional<float> repeat_length)
|
||||
{
|
||||
fill_rect_with_linear_gradient(rect.to_type<float>(), stops, angle, repeat_length);
|
||||
}
|
||||
|
||||
void Painter::fill_rect_with_linear_gradient(Gfx::FloatRect const& rect, ReadonlySpan<Gfx::ColorStop> stops, float angle, Optional<float> repeat_length)
|
||||
{
|
||||
// FIXME: Implement support for angle and repeat_length
|
||||
(void)angle;
|
||||
(void)repeat_length;
|
||||
|
||||
Vector<GLfloat> vertices;
|
||||
Vector<GLfloat> colors;
|
||||
for (size_t stop_index = 0; stop_index < stops.size() - 1; stop_index++) {
|
||||
auto const& stop_start = stops[stop_index];
|
||||
auto const& stop_end = stops[stop_index + 1];
|
||||
|
||||
// The gradient is divided into segments that represent linear gradients between adjacent pairs of stops.
|
||||
auto segment_rect_location = rect.location();
|
||||
segment_rect_location.set_x(segment_rect_location.x() + stop_start.position * rect.width());
|
||||
auto segment_rect_width = (stop_end.position - stop_start.position) * rect.width();
|
||||
auto segment_rect_height = rect.height();
|
||||
auto segment_rect = Gfx::FloatRect { segment_rect_location.x(), segment_rect_location.y(), segment_rect_width, segment_rect_height };
|
||||
|
||||
auto rect_in_clip_space = to_clip_space(segment_rect);
|
||||
|
||||
// p0 --- p1
|
||||
// | \ |
|
||||
// | \ |
|
||||
// | \ |
|
||||
// p2 --- p3
|
||||
|
||||
auto p0 = rect_in_clip_space.top_left();
|
||||
auto p1 = rect_in_clip_space.top_right();
|
||||
auto p2 = rect_in_clip_space.bottom_left();
|
||||
auto p3 = rect_in_clip_space.bottom_right();
|
||||
|
||||
auto c0 = gfx_color_to_opengl_color(stop_start.color);
|
||||
auto c1 = gfx_color_to_opengl_color(stop_end.color);
|
||||
auto c2 = gfx_color_to_opengl_color(stop_start.color);
|
||||
auto c3 = gfx_color_to_opengl_color(stop_end.color);
|
||||
|
||||
auto add_triangle = [&](auto& p1, auto& p2, auto& p3, auto& c1, auto& c2, auto& c3) {
|
||||
vertices.append(p1.x());
|
||||
vertices.append(p1.y());
|
||||
colors.append(c1.red);
|
||||
colors.append(c1.green);
|
||||
colors.append(c1.blue);
|
||||
colors.append(c1.alpha);
|
||||
|
||||
vertices.append(p2.x());
|
||||
vertices.append(p2.y());
|
||||
colors.append(c2.red);
|
||||
colors.append(c2.green);
|
||||
colors.append(c2.blue);
|
||||
colors.append(c2.alpha);
|
||||
|
||||
vertices.append(p3.x());
|
||||
vertices.append(p3.y());
|
||||
colors.append(c3.red);
|
||||
colors.append(c3.green);
|
||||
colors.append(c3.blue);
|
||||
colors.append(c3.alpha);
|
||||
};
|
||||
|
||||
add_triangle(p0, p1, p3, c0, c1, c3);
|
||||
add_triangle(p0, p3, p2, c0, c3, c2);
|
||||
}
|
||||
|
||||
auto vao = GL::create_vertex_array();
|
||||
GL::bind_vertex_array(vao);
|
||||
|
||||
auto vbo_vertices = GL::create_buffer();
|
||||
GL::upload_to_buffer(vbo_vertices, vertices);
|
||||
|
||||
auto vbo_colors = GL::create_buffer();
|
||||
GL::upload_to_buffer(vbo_colors, colors);
|
||||
|
||||
m_linear_gradient_program.use();
|
||||
auto position_attribute = m_linear_gradient_program.get_attribute_location("aVertexPosition");
|
||||
auto color_attribute = m_linear_gradient_program.get_attribute_location("aColor");
|
||||
|
||||
GL::bind_buffer(vbo_vertices);
|
||||
GL::set_vertex_attribute(position_attribute, 0, 2);
|
||||
|
||||
GL::bind_buffer(vbo_colors);
|
||||
GL::set_vertex_attribute(color_attribute, 0, 4);
|
||||
|
||||
GL::draw_arrays(GL::DrawPrimitive::Triangles, vertices.size() / 2);
|
||||
}
|
||||
|
||||
void Painter::save()
|
||||
{
|
||||
m_state_stack.append(state());
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <LibGfx/AffineTransform.h>
|
||||
#include <LibGfx/Font/Font.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
#include <LibGfx/Gradients.h>
|
||||
#include <LibGfx/TextLayout.h>
|
||||
|
||||
namespace AccelGfx {
|
||||
|
@ -73,6 +74,9 @@ public:
|
|||
void set_target_bitmap(Gfx::Bitmap&);
|
||||
void flush();
|
||||
|
||||
void fill_rect_with_linear_gradient(Gfx::IntRect const&, ReadonlySpan<Gfx::ColorStop>, float angle, Optional<float> repeat_length = {});
|
||||
void fill_rect_with_linear_gradient(Gfx::FloatRect const&, ReadonlySpan<Gfx::ColorStop>, float angle, Optional<float> repeat_length = {});
|
||||
|
||||
private:
|
||||
Context& m_context;
|
||||
|
||||
|
@ -89,6 +93,7 @@ private:
|
|||
|
||||
Program m_rectangle_program;
|
||||
Program m_blit_program;
|
||||
Program m_linear_gradient_program;
|
||||
|
||||
HashMap<GlyphsTextureKey, Gfx::IntRect> m_glyphs_texture_map;
|
||||
Gfx::IntSize m_glyphs_texture_size;
|
||||
|
|
|
@ -99,9 +99,9 @@ CommandResult PaintingCommandExecutorGPU::pop_stacking_context_with_mask(Gfx::In
|
|||
return CommandResult::Continue;
|
||||
}
|
||||
|
||||
CommandResult PaintingCommandExecutorGPU::paint_linear_gradient(Gfx::IntRect const&, Web::Painting::LinearGradientData const&)
|
||||
CommandResult PaintingCommandExecutorGPU::paint_linear_gradient(Gfx::IntRect const& rect, Web::Painting::LinearGradientData const& data)
|
||||
{
|
||||
// FIXME
|
||||
painter().fill_rect_with_linear_gradient(rect, data.color_stops.list, data.gradient_angle, data.color_stops.repeat_length);
|
||||
return CommandResult::Continue;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue