| Flutter Impeller |

line_geometry.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "impeller/entity/geometry/line_geometry.h"
6 #include "impeller/entity/contents/pipelines.h"
7 #include "impeller/entity/geometry/geometry.h"
8
9 namespace impeller {
10
11 LineGeometry::LineGeometry(Point p0, Point p1, Scalar width, Cap cap)
12 : p0_(p0), p1_(p1), width_(width), cap_(cap) {
13 FML_DCHECK(width >= 0);
14 }
15
16 LineGeometry::~LineGeometry() = default;
17
18 Scalar LineGeometry::ComputePixelHalfWidth(const Matrix& transform,
19 Scalar width) {
20 Scalar max_basis = transform.GetMaxBasisLengthXY();
21 if (max_basis == 0) {
22 return {};
23 }
24
25 Scalar min_size = kMinStrokeSize / max_basis;
26 return std::max(width, min_size) * 0.5f;
27 }
28
29 Vector2 LineGeometry::ComputeAlongVector(const Matrix& transform,
30 bool allow_zero_length,
31 Point p0,
32 Point p1,
33 Scalar width) {
34 Scalar stroke_half_width = ComputePixelHalfWidth(transform, width);
35 if (stroke_half_width < kEhCloseEnough) {
36 return {};
37 }
38
39 auto along = p1 - p0;
40 Scalar length = along.GetLength();
41 if (length < kEhCloseEnough) {
42 if (!allow_zero_length) {
43 // We won't enclose any pixels unless the endpoints are extended
44 return {};
45 }
46 return {stroke_half_width, 0};
47 } else {
48 return along * stroke_half_width / length;
49 }
50 }
51
52 bool LineGeometry::ComputeCorners(Point corners[4],
53 const Matrix& transform,
54 bool extend_endpoints,
55 Point p0,
56 Point p1,
57 Scalar width) {
58 auto along = ComputeAlongVector(transform, extend_endpoints, p0, p1, width);
59 if (along.IsZero()) {
60 return false;
61 }
62
63 auto across = Vector2(along.y, -along.x);
64 corners[0] = p0 - across;
65 corners[1] = p1 - across;
66 corners[2] = p0 + across;
67 corners[3] = p1 + across;
68 if (extend_endpoints) {
69 corners[0] -= along;
70 corners[1] += along;
71 corners[2] -= along;
72 corners[3] += along;
73 }
74 return true;
75 }
76
77 Scalar LineGeometry::ComputeAlphaCoverage(const Matrix& entity) const {
78 return Geometry::ComputeStrokeAlphaCoverage(entity, width_);
79 }
80
81 namespace {
82 /// Minimizes the err when rounding to the closest 0.5 value.
83 /// If we round up, it drops down a half. If we round down it bumps up a half.
84 Scalar RoundToHalf(Scalar x) {
85 Scalar whole;
86 std::modf(x, &whole);
87 return whole + 0.5;
88 }
89 } // namespace
90
91 GeometryResult LineGeometry::GetPositionBuffer(const ContentContext& renderer,
92 const Entity& entity,
93 RenderPass& pass) const {
94 using VT = SolidFillVertexShader::PerVertexData;
95
96 Matrix transform = entity.GetTransform();
97 auto radius = ComputePixelHalfWidth(transform, width_);
98
99 Point p0 = p0_;
100 Point p1 = p1_;
101
102 // Hairline pixel alignment.
103 if (width_ == 0.f && transform.IsTranslationScaleOnly()) {
104 p0 = transform * p0_;
105 p1 = transform * p1_;
106 transform = Matrix();
107 if (std::fabs(p0.x - p1.x) < kEhCloseEnough) {
108 p0.x = RoundToHalf(p0.x);
109 p1.x = p0.x;
110 } else if (std::fabs(p0.y - p1.y) < kEhCloseEnough) {
111 p0.y = RoundToHalf(p0.y);
112 p1.y = p0.y;
113 }
114 }
115
116 Entity fixed_transform = entity.Clone();
117 fixed_transform.SetTransform(transform);
118
119 if (cap_ == Cap::kRound) {
120 auto generator =
121 renderer.GetTessellator().RoundCapLine(transform, p0, p1, radius);
122 return ComputePositionGeometry(renderer, generator, fixed_transform, pass);
123 }
124
125 Point corners[4];
126 if (!ComputeCorners(corners, transform, cap_ == Cap::kSquare, p0, p1,
127 width_)) {
128 return kEmptyResult;
129 }
130
131 auto& host_buffer = renderer.GetTransientsBuffer();
132
133 size_t count = 4;
134 BufferView vertex_buffer = host_buffer.Emplace(
135 count * sizeof(VT), alignof(VT), [&corners](uint8_t* buffer) {
136 auto vertices = reinterpret_cast<VT*>(buffer);
137 for (auto& corner : corners) {
138 *vertices++ = {
139 .position = corner,
140 };
141 }
142 });
143
144 return GeometryResult{
145 .type = PrimitiveType::kTriangleStrip,
146 .vertex_buffer =
147 {
148 .vertex_buffer = vertex_buffer,
149 .vertex_count = count,
150 .index_type = IndexType::kNone,
151 },
152 .transform = fixed_transform.GetShaderTransform(pass),
153 };
154 }
155
156 std::optional<Rect> LineGeometry::GetCoverage(const Matrix& transform) const {
157 Point corners[4];
158 // Note: MSAA boolean doesn't matter for coverage computation.
159 if (!ComputeCorners(corners, transform, cap_ != Cap::kButt, p0_, p1_,
160 width_)) {
161 return {};
162 }
163
164 for (int i = 0; i < 4; i++) {
165 corners[i] = transform * corners[i];
166 }
167 return Rect::MakePointBounds(std::begin(corners), std::end(corners));
168 }
169
170 bool LineGeometry::CoversArea(const Matrix& transform, const Rect& rect) const {
171 if (!transform.IsTranslationScaleOnly() || !IsAxisAlignedRect()) {
172 return false;
173 }
174 auto coverage = GetCoverage(transform);
175 return coverage.has_value() ? coverage->Contains(rect) : false;
176 }
177
178 bool LineGeometry::IsAxisAlignedRect() const {
179 return cap_ != Cap::kRound && (p0_.x == p1_.x || p0_.y == p1_.y);
180 }
181
182 } // namespace impeller
impeller::Geometry::ComputeStrokeAlphaCoverage
static Scalar ComputeStrokeAlphaCoverage(const Matrix &entity, Scalar stroke_width)
Compute an alpha value to simulate lower coverage of fractional pixel strokes.
Definition: geometry.cc:134
impeller::Geometry::ComputePositionGeometry
static GeometryResult ComputePositionGeometry(const ContentContext &renderer, const Tessellator::VertexGenerator &generator, const Entity &entity, RenderPass &pass)
Definition: geometry.cc:25
impeller::LineGeometry::~LineGeometry
~LineGeometry() override
impeller::LineGeometry::LineGeometry
LineGeometry(Point p0, Point p1, Scalar width, Cap cap)
Definition: line_geometry.cc:11
impeller::LineGeometry::ComputeAlongVector
static Vector2 ComputeAlongVector(const Matrix &transform, bool allow_zero_length, Point p0, Point p1, Scalar width)
Definition: line_geometry.cc:29
impeller::LineGeometry::ComputePixelHalfWidth
static Scalar ComputePixelHalfWidth(const Matrix &transform, Scalar width)
Definition: line_geometry.cc:18
impeller::LineGeometry::IsAxisAlignedRect
bool IsAxisAlignedRect() const override
Definition: line_geometry.cc:178
impeller::LineGeometry::ComputeAlphaCoverage
Scalar ComputeAlphaCoverage(const Matrix &transform) const override
Definition: line_geometry.cc:77
impeller::LineGeometry::ComputeCorners
static bool ComputeCorners(Point corners[4], const Matrix &transform, bool extend_endpoints, Point p0, Point p1, Scalar width)
Definition: line_geometry.cc:52
impeller::LineGeometry::GetCoverage
std::optional< Rect > GetCoverage(const Matrix &transform) const override
Definition: line_geometry.cc:156
impeller::LineGeometry::CoversArea
bool CoversArea(const Matrix &transform, const Rect &rect) const override
Determines if this geometry, transformed by the given transform, will completely cover all surface ar...
Definition: line_geometry.cc:170
x
int32_t x
Definition: dl_golden_unittests.cc:458
transform
Matrix transform
Definition: gaussian_blur_filter_contents.cc:214
geometry.h
line_geometry.h
impeller
Definition: allocation.cc:12
impeller::IndexType::kNone
@ kNone
Does not use the index buffer.
impeller::PrimitiveType::kTriangleStrip
@ kTriangleStrip
impeller::Vector2
Point Vector2
Definition: point.h:331
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::kEhCloseEnough
constexpr float kEhCloseEnough
Definition: constants.h:57
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
impeller::Cap
Cap
Definition: path.h:20
impeller::Cap::kRound
@ kRound
impeller::Cap::kButt
@ kButt
impeller::Cap::kSquare
@ kSquare
impeller::kEmptyResult
static const GeometryResult kEmptyResult
Definition: geometry.h:43
impeller::kMinStrokeSize
static constexpr Scalar kMinStrokeSize
Definition: geometry.h:19
pipelines.h
impeller::GeometryResult::type
PrimitiveType type
Definition: geometry.h:37
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::TPoint< Scalar >
impeller::TPoint::GetLength
constexpr Type GetLength() const
Definition: point.h:206
impeller::TRect< Scalar >
impeller::TRect< Scalar >::MakePointBounds
constexpr static std::optional< TRect > MakePointBounds(const U &value)
Definition: rect.h:165