mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Rendering of continuous strokes.
This commit is contained in:
parent
76b8ca7ca1
commit
75daec6e7b
@ -81,6 +81,18 @@ TEST_F(AiksTest, CanRenderStrokes) {
|
||||
Paint paint;
|
||||
paint.color = Color::Red();
|
||||
paint.stroke_width = 20.0;
|
||||
paint.style = Paint::Style::kStroke;
|
||||
canvas.DrawPath(PathBuilder{}.AddLine({200, 100}, {800, 100}).CreatePath(),
|
||||
paint);
|
||||
// ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
TEST_F(AiksTest, CanRenderCurvedStrokes) {
|
||||
Canvas canvas;
|
||||
Paint paint;
|
||||
paint.color = Color::Blue();
|
||||
paint.stroke_width = 25.0;
|
||||
paint.style = Paint::Style::kStroke;
|
||||
canvas.DrawPath(PathBuilder{}.AddCircle({500, 500}, 250).CreatePath(), paint);
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
@ -12,6 +12,8 @@ impeller_shaders("entity_shaders") {
|
||||
"shaders/gradient_fill.vert",
|
||||
"shaders/solid_fill.frag",
|
||||
"shaders/solid_fill.vert",
|
||||
"shaders/solid_stroke.frag",
|
||||
"shaders/solid_stroke.vert",
|
||||
"shaders/texture_fill.frag",
|
||||
"shaders/texture_fill.vert",
|
||||
]
|
||||
|
||||
@ -15,6 +15,7 @@ ContentRenderer::ContentRenderer(std::shared_ptr<Context> context)
|
||||
gradient_fill_pipeline_ = std::make_unique<GradientFillPipeline>(*context_);
|
||||
solid_fill_pipeline_ = std::make_unique<SolidFillPipeline>(*context_);
|
||||
texture_pipeline_ = std::make_unique<TexturePipeline>(*context_);
|
||||
solid_stroke_pipeline_ = std::make_unique<SolidStrokePipeline>(*context_);
|
||||
|
||||
is_valid_ = true;
|
||||
}
|
||||
@ -52,4 +53,12 @@ std::shared_ptr<Pipeline> ContentRenderer::GetTexturePipeline() const {
|
||||
return texture_pipeline_->WaitAndGet();
|
||||
}
|
||||
|
||||
std::shared_ptr<Pipeline> ContentRenderer::GetSolidStrokePipeline() const {
|
||||
if (!IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return solid_stroke_pipeline_->WaitAndGet();
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@ -11,6 +11,8 @@
|
||||
#include "flutter/impeller/entity/gradient_fill.vert.h"
|
||||
#include "flutter/impeller/entity/solid_fill.frag.h"
|
||||
#include "flutter/impeller/entity/solid_fill.vert.h"
|
||||
#include "flutter/impeller/entity/solid_stroke.frag.h"
|
||||
#include "flutter/impeller/entity/solid_stroke.vert.h"
|
||||
#include "flutter/impeller/entity/texture_fill.frag.h"
|
||||
#include "flutter/impeller/entity/texture_fill.vert.h"
|
||||
#include "impeller/renderer/pipeline.h"
|
||||
@ -23,6 +25,8 @@ using SolidFillPipeline =
|
||||
PipelineT<SolidFillVertexShader, SolidFillFragmentShader>;
|
||||
using TexturePipeline =
|
||||
PipelineT<TextureFillVertexShader, TextureFillFragmentShader>;
|
||||
using SolidStrokePipeline =
|
||||
PipelineT<SolidStrokeVertexShader, SolidStrokeFragmentShader>;
|
||||
|
||||
class ContentRenderer {
|
||||
public:
|
||||
@ -38,6 +42,8 @@ class ContentRenderer {
|
||||
|
||||
std::shared_ptr<Pipeline> GetTexturePipeline() const;
|
||||
|
||||
std::shared_ptr<Pipeline> GetSolidStrokePipeline() const;
|
||||
|
||||
std::shared_ptr<Context> GetContext() const;
|
||||
|
||||
private:
|
||||
@ -45,6 +51,7 @@ class ContentRenderer {
|
||||
std::unique_ptr<GradientFillPipeline> gradient_fill_pipeline_;
|
||||
std::unique_ptr<SolidFillPipeline> solid_fill_pipeline_;
|
||||
std::unique_ptr<TexturePipeline> texture_pipeline_;
|
||||
std::unique_ptr<SolidStrokePipeline> solid_stroke_pipeline_;
|
||||
bool is_valid_ = false;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(ContentRenderer);
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
#include "impeller/entity/content_renderer.h"
|
||||
#include "impeller/entity/entity.h"
|
||||
#include "impeller/geometry/path_builder.h"
|
||||
#include "impeller/geometry/vector.h"
|
||||
#include "impeller/renderer/render_pass.h"
|
||||
#include "impeller/renderer/sampler_library.h"
|
||||
#include "impeller/renderer/surface.h"
|
||||
@ -236,13 +237,11 @@ bool TextureContents::Render(const ContentRenderer& renderer,
|
||||
frame_info.mvp =
|
||||
Matrix::MakeOrthographic(surface.GetSize()) * entity.GetTransformation();
|
||||
|
||||
auto frame_info_view = host_buffer.EmplaceUniform(frame_info);
|
||||
|
||||
Command cmd;
|
||||
cmd.label = "TextureFill";
|
||||
cmd.pipeline = renderer.GetTexturePipeline();
|
||||
cmd.BindVertices(vertex_builder.CreateVertexBuffer(host_buffer));
|
||||
VS::BindFrameInfo(cmd, frame_info_view);
|
||||
VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info));
|
||||
FS::BindTextureSampler(
|
||||
cmd, texture_,
|
||||
renderer.GetContext()->GetSamplerLibrary()->GetSampler({}));
|
||||
@ -275,6 +274,45 @@ const Color& SolidStrokeContents::GetColor() const {
|
||||
return color_;
|
||||
}
|
||||
|
||||
static VertexBuffer CreateSolidStrokeVertices(const Path& path,
|
||||
HostBuffer& buffer) {
|
||||
using VS = SolidStrokeVertexShader;
|
||||
|
||||
VertexBufferBuilder<VS::PerVertexData> vtx_builder;
|
||||
auto polyline = path.CreatePolyline();
|
||||
|
||||
for (size_t i = 0, polyline_size = polyline.size(); i < polyline_size; i++) {
|
||||
const auto is_last_point = i == polyline_size - 1;
|
||||
|
||||
const auto& p1 = polyline[i];
|
||||
const auto& p2 = is_last_point ? polyline[i - 1] : polyline[i + 1];
|
||||
|
||||
const auto diff = p2 - p1;
|
||||
|
||||
const Scalar direction = is_last_point ? -1.0 : 1.0;
|
||||
|
||||
const auto normal =
|
||||
Point{-diff.y * direction, diff.x * direction}.Normalize();
|
||||
|
||||
VS::PerVertexData vtx;
|
||||
vtx.vertex_position = p1;
|
||||
|
||||
if (i == 0) {
|
||||
vtx.vertex_normal = -normal;
|
||||
vtx_builder.AppendVertex(vtx);
|
||||
vtx.vertex_normal = normal;
|
||||
vtx_builder.AppendVertex(vtx);
|
||||
}
|
||||
|
||||
vtx.vertex_normal = normal;
|
||||
vtx_builder.AppendVertex(vtx);
|
||||
vtx.vertex_normal = -normal;
|
||||
vtx_builder.AppendVertex(vtx);
|
||||
}
|
||||
|
||||
return vtx_builder.CreateVertexBuffer(buffer);
|
||||
}
|
||||
|
||||
bool SolidStrokeContents::Render(const ContentRenderer& renderer,
|
||||
const Entity& entity,
|
||||
const Surface& surface,
|
||||
@ -283,7 +321,29 @@ bool SolidStrokeContents::Render(const ContentRenderer& renderer,
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
using VS = SolidStrokeVertexShader;
|
||||
|
||||
VS::FrameInfo frame_info;
|
||||
frame_info.mvp =
|
||||
Matrix::MakeOrthographic(surface.GetSize()) * entity.GetTransformation();
|
||||
|
||||
VS::StrokeInfo stroke_info;
|
||||
stroke_info.color = color_;
|
||||
stroke_info.size = stroke_size_;
|
||||
|
||||
Command cmd;
|
||||
cmd.primitive_type = PrimitiveType::kTriangleStrip;
|
||||
cmd.label = "SolidStroke";
|
||||
cmd.pipeline = renderer.GetSolidStrokePipeline();
|
||||
cmd.BindVertices(
|
||||
CreateSolidStrokeVertices(entity.GetPath(), pass.GetTransientsBuffer()));
|
||||
VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info));
|
||||
VS::BindStrokeInfo(cmd,
|
||||
pass.GetTransientsBuffer().EmplaceUniform(stroke_info));
|
||||
|
||||
pass.AddCommand(std::move(cmd));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SolidStrokeContents::SetStrokeSize(Scalar size) {
|
||||
|
||||
11
engine/src/flutter/impeller/entity/shaders/solid_stroke.frag
Normal file
11
engine/src/flutter/impeller/entity/shaders/solid_stroke.frag
Normal file
@ -0,0 +1,11 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
in vec4 stroke_color;
|
||||
|
||||
out vec4 frag_color;
|
||||
|
||||
void main() {
|
||||
frag_color = stroke_color;
|
||||
}
|
||||
23
engine/src/flutter/impeller/entity/shaders/solid_stroke.vert
Normal file
23
engine/src/flutter/impeller/entity/shaders/solid_stroke.vert
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
uniform FrameInfo {
|
||||
mat4 mvp;
|
||||
} frame_info;
|
||||
|
||||
uniform StrokeInfo {
|
||||
vec4 color;
|
||||
float size;
|
||||
} stroke_info;
|
||||
|
||||
in vec2 vertex_position;
|
||||
in vec2 vertex_normal;
|
||||
|
||||
out vec4 stroke_color;
|
||||
|
||||
void main() {
|
||||
vec2 offset = vertex_normal * vec2(stroke_info.size * 0.5);
|
||||
gl_Position = frame_info.mvp * vec4(vertex_position + offset, 0.0, 1.0);
|
||||
stroke_color = stroke_info.color;
|
||||
}
|
||||
@ -298,6 +298,11 @@ PathBuilder& PathBuilder::AddOval(const Rect& container) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
PathBuilder& PathBuilder::AddLine(const Point& p1, const Point& p2) {
|
||||
prototype_.AddLinearComponent(p1, p2);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Path& PathBuilder::GetCurrentPath() const {
|
||||
return prototype_;
|
||||
}
|
||||
|
||||
@ -54,6 +54,8 @@ class PathBuilder {
|
||||
|
||||
PathBuilder& AddOval(const Rect& rect);
|
||||
|
||||
PathBuilder& AddLine(const Point& p1, const Point& p2);
|
||||
|
||||
struct RoundingRadii {
|
||||
Scalar topLeft = 0.0;
|
||||
Scalar bottomLeft = 0.0;
|
||||
|
||||
@ -86,6 +86,18 @@ struct TPoint {
|
||||
constexpr Type GetDistance(const TPoint& p) const {
|
||||
return sqrt(GetDistanceSquared(p));
|
||||
}
|
||||
|
||||
constexpr Type GetLengthSquared() const { return GetDistanceSquared({}); }
|
||||
|
||||
constexpr Type GetLength() const { return GetDistance({}); }
|
||||
|
||||
constexpr TPoint Normalize() const {
|
||||
const auto length = GetLength();
|
||||
if (length == 0) {
|
||||
return {};
|
||||
}
|
||||
return {x / length, y / length};
|
||||
}
|
||||
};
|
||||
|
||||
using Point = TPoint<Scalar>;
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
|
||||
#include <Metal/Metal.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/renderer/backend/metal/backend_cast.h"
|
||||
#include "impeller/renderer/vertex_descriptor.h"
|
||||
@ -28,8 +30,15 @@ class VertexDescriptorMTL {
|
||||
|
||||
StageInput(size_t p_location, MTLVertexFormat p_format, size_t p_length)
|
||||
: location(p_location), format(p_format), length(p_length) {}
|
||||
|
||||
struct Compare {
|
||||
constexpr bool operator()(const StageInput& lhs,
|
||||
const StageInput& rhs) const {
|
||||
return lhs.location < rhs.location;
|
||||
}
|
||||
};
|
||||
};
|
||||
std::vector<StageInput> stage_inputs_;
|
||||
std::set<StageInput, StageInput::Compare> stage_inputs_;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(VertexDescriptorMTL);
|
||||
};
|
||||
|
||||
@ -179,8 +179,9 @@ bool VertexDescriptorMTL::SetStageInputs(
|
||||
FML_LOG(ERROR) << "Format for input " << input.name << " not supported.";
|
||||
return false;
|
||||
}
|
||||
stage_inputs_.emplace_back(StageInput{
|
||||
input.location, vertex_format, (input.bit_width * input.vec_size) / 8});
|
||||
|
||||
stage_inputs_.insert(StageInput{input.location, vertex_format,
|
||||
(input.bit_width * input.vec_size) / 8});
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@ -50,6 +50,8 @@ struct ShaderUniformSlot {
|
||||
|
||||
struct ShaderStageIOSlot {
|
||||
// Statically allocated const string containing advisory debug description.
|
||||
// This may be absent in release modes and the runtime may not use this string
|
||||
// for normal operation.
|
||||
const char* name;
|
||||
size_t location;
|
||||
size_t set;
|
||||
|
||||
@ -35,6 +35,8 @@ class VertexBufferBuilder {
|
||||
|
||||
bool HasVertices() const { return !vertices_.empty(); }
|
||||
|
||||
size_t GetVertexCount() const { return vertices_.size(); }
|
||||
|
||||
VertexBufferBuilder& AppendVertex(VertexType_ vertex) {
|
||||
vertices_.emplace_back(std::move(vertex));
|
||||
return *this;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user