Flutter Impeller
rect_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 
6 
7 namespace impeller {
8 
10 
12 
14  const ContentContext& renderer,
15  const Entity& entity,
16  RenderPass& pass) const {
17  auto& host_buffer = renderer.GetTransientsBuffer();
18  return GeometryResult{
20  .vertex_buffer =
21  {
22  .vertex_buffer = host_buffer.Emplace(
23  rect_.GetPoints().data(), 8 * sizeof(float), alignof(float)),
24  .vertex_count = 4,
25  .index_type = IndexType::kNone,
26  },
27  .transform = entity.GetShaderTransform(pass),
28  };
29 }
30 
31 std::optional<Rect> FillRectGeometry::GetCoverage(
32  const Matrix& transform) const {
33  return rect_.TransformBounds(transform);
34 }
35 
37  const Rect& rect) const {
38  if (!transform.IsTranslationScaleOnly()) {
39  return false;
40  }
41  Rect coverage = rect_.TransformBounds(transform);
42  return coverage.Contains(rect);
43 }
44 
46  return true;
47 }
48 
50  const StrokeParameters& stroke)
51  : rect_(rect),
52  stroke_width_(stroke.width),
53  stroke_join_(AdjustStrokeJoin(stroke)) {}
54 
56 
58  const ContentContext& renderer,
59  const Entity& entity,
60  RenderPass& pass) const {
61  if (stroke_width_ < 0.0) {
62  return {};
63  }
64  Scalar max_basis = entity.GetTransform().GetMaxBasisLengthXY();
65  if (max_basis == 0) {
66  return {};
67  }
68 
69  Scalar min_size = kMinStrokeSize / max_basis;
70  Scalar half_stroke_width = std::max(stroke_width_, min_size) * 0.5f;
71 
72  auto& host_buffer = renderer.GetTransientsBuffer();
73  const Rect& rect = rect_;
74 
75  switch (stroke_join_) {
76  case Join::kRound: {
77  Tessellator::Trigs trigs =
78  renderer.GetTessellator().GetTrigsForDeviceRadius(half_stroke_width *
79  max_basis);
80 
81  FML_DCHECK(trigs.size() >= 2u);
82 
83  // We use all but the first entry in trigs for each corner.
84  auto vertex_count = trigs.size() - 1;
85  // Every other point has a center vertex added.
86  vertex_count = vertex_count + (vertex_count >> 1);
87  // The loop also adds 3 points of its own.
88  vertex_count += 3;
89  // We do that for each of the 4 corners.
90  vertex_count = vertex_count * 4;
91  // We then add 2 more points at the end to close the last edge.
92  vertex_count += 2;
93 
94  return GeometryResult{
96  .vertex_buffer =
97  {
98  .vertex_buffer = host_buffer.Emplace(
99  vertex_count * sizeof(Point), alignof(Point),
100  [hsw = half_stroke_width, &rect, vertex_count,
101  &trigs](uint8_t* buffer) {
102  auto vertices = reinterpret_cast<Point*>(buffer);
103  [[maybe_unused]]
104  auto vertices_end = vertices + vertex_count;
105 
106  vertices =
107  AppendRoundCornerJoin(vertices, rect.GetLeftTop(),
108  Vector2(-hsw, 0), trigs);
109  vertices =
110  AppendRoundCornerJoin(vertices, rect.GetRightTop(),
111  Vector2(0, -hsw), trigs);
112  vertices = AppendRoundCornerJoin(
113  vertices, rect.GetRightBottom(), Vector2(hsw, 0),
114  trigs);
115  vertices = AppendRoundCornerJoin(
116  vertices, rect.GetLeftBottom(), Vector2(0, hsw),
117  trigs);
118 
119  // Repeat the first 2 points from the first corner to
120  // close the last edge.
121  *vertices++ = rect.GetLeftTop() - Vector2(hsw, 0);
122  *vertices++ = rect.GetLeftTop() + Vector2(hsw, 0);
123 
124  // Make sure our estimate is always up to date.
125  FML_DCHECK(vertices == vertices_end);
126  }),
127  .vertex_count = vertex_count,
128  .index_type = IndexType::kNone,
129  },
130  .transform = entity.GetShaderTransform(pass),
131  };
132  }
133 
134  case Join::kBevel: {
135  return GeometryResult{
137  .vertex_buffer =
138  {
139  .vertex_buffer = host_buffer.Emplace(
140  17 * sizeof(Point), alignof(Point),
141  [hsw = half_stroke_width, &rect](uint8_t* buffer) {
142  Scalar left = rect.GetLeft();
143  Scalar top = rect.GetTop();
144  Scalar right = rect.GetRight();
145  Scalar bottom = rect.GetBottom();
146  auto vertices = reinterpret_cast<Point*>(buffer);
147  vertices[0] = Point(left, top - hsw);
148  vertices[1] = Point(left, top + hsw);
149  vertices[2] = Point(right, top - hsw);
150  vertices[3] = Point(right, top + hsw);
151  vertices[4] = Point(right + hsw, top);
152  vertices[5] = Point(right - hsw, top);
153  vertices[6] = Point(right + hsw, bottom);
154  vertices[7] = Point(right - hsw, bottom);
155  vertices[8] = Point(right, bottom + hsw);
156  vertices[9] = Point(right, bottom - hsw);
157  vertices[10] = Point(left, bottom + hsw);
158  vertices[11] = Point(left, bottom - hsw);
159  vertices[12] = Point(left - hsw, bottom);
160  vertices[13] = Point(left + hsw, bottom);
161  vertices[14] = Point(left - hsw, top);
162  vertices[15] = Point(left + hsw, top);
163  vertices[16] = Point(left, top - hsw);
164  }),
165  .vertex_count = 17u,
166  .index_type = IndexType::kNone,
167  },
168  .transform = entity.GetShaderTransform(pass),
169  };
170  }
171 
172  case Join::kMiter: {
173  return GeometryResult{
175  .vertex_buffer =
176  {
177  .vertex_buffer = host_buffer.Emplace(
178  10 * sizeof(Point), alignof(Point),
179  [hsw = half_stroke_width, &rect](uint8_t* buffer) {
180  Scalar left = rect.GetLeft();
181  Scalar top = rect.GetTop();
182  Scalar right = rect.GetRight();
183  Scalar bottom = rect.GetBottom();
184  auto vertices = reinterpret_cast<Point*>(buffer);
185  vertices[0] = Point(left - hsw, top - hsw);
186  vertices[1] = Point(left + hsw, top + hsw);
187  vertices[2] = Point(right + hsw, top - hsw);
188  vertices[3] = Point(right - hsw, top + hsw);
189  vertices[4] = Point(right + hsw, bottom + hsw);
190  vertices[5] = Point(right - hsw, bottom - hsw);
191  vertices[6] = Point(left - hsw, bottom + hsw);
192  vertices[7] = Point(left + hsw, bottom - hsw);
193  vertices[8] = Point(left - hsw, top - hsw);
194  vertices[9] = Point(left + hsw, top + hsw);
195  }),
196  .vertex_count = 10u,
197  .index_type = IndexType::kNone,
198  },
199  .transform = entity.GetShaderTransform(pass),
200  };
201  }
202  }
203 }
204 
206  const Matrix& transform) const {
207  return rect_.TransformBounds(transform);
208 }
209 
210 Join StrokeRectGeometry::AdjustStrokeJoin(const StrokeParameters& stroke) {
211  return (stroke.join == Join::kMiter && stroke.miter_limit < kSqrt2)
212  ? Join::kBevel
213  : stroke.join;
214 }
215 
216 Point* StrokeRectGeometry::AppendRoundCornerJoin(
217  Point* buffer,
218  Point corner,
219  Vector2 offset,
220  const Tessellator::Trigs& trigs) {
221  // Close the edge box set up by the end of the last corner and
222  // set up the first wedge of this corner.
223  *buffer++ = corner + offset;
224  *buffer++ = corner - offset;
225  bool do_center = false;
226  auto trig = trigs.begin();
227  auto end = trigs.end();
228  while (++trig < end) {
229  if (do_center) {
230  *buffer++ = corner;
231  }
232  do_center = !do_center;
233  *buffer++ = corner + *trig * offset;
234  }
235  // Together with the last point pushed by the loop we set up to
236  // initiate the edge box connecting to the next corner.
237  *buffer++ = corner - end[-1] * offset;
238  return buffer;
239 }
240 
241 } // namespace impeller
HostBuffer & GetTransientsBuffer() const
Retrieve the currnent host buffer for transient storage.
Tessellator & GetTessellator() const
Matrix GetShaderTransform(const RenderPass &pass) const
Definition: entity.cc:48
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
Definition: entity.cc:44
std::optional< Rect > GetCoverage(const Matrix &transform) const override
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...
bool IsAxisAlignedRect() const override
GeometryResult GetPositionBuffer(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const override
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:30
std::optional< Rect > GetCoverage(const Matrix &transform) const override
StrokeRectGeometry(const Rect &rect, const StrokeParameters &stroke)
GeometryResult GetPositionBuffer(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const override
Trigs GetTrigsForDeviceRadius(Scalar pixel_radius)
Definition: tessellator.cc:310
@ kNone
Does not use the index buffer.
Join
An enum that describes ways to join two segments of a path.
Point Vector2
Definition: point.h:331
float Scalar
Definition: scalar.h:19
TPoint< Scalar > Point
Definition: point.h:327
constexpr float kSqrt2
Definition: constants.h:47
static constexpr Scalar kMinStrokeSize
Definition: geometry.h:19
PrimitiveType type
Definition: geometry.h:37
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
Scalar GetMaxBasisLengthXY() const
Definition: matrix.h:323
A structure to store all of the parameters related to stroking a path or basic geometry object.
constexpr auto GetBottom() const
Definition: rect.h:361
constexpr TRect TransformBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle.
Definition: rect.h:476
constexpr auto GetTop() const
Definition: rect.h:357
constexpr bool Contains(const TPoint< Type > &p) const
Returns true iff the provided point |p| is inside the half-open interior of this rectangle.
Definition: rect.h:235
constexpr std::array< TPoint< T >, 4 > GetPoints() const
Get the points that represent the 4 corners of this rectangle in a Z order that is compatible with tr...
Definition: rect.h:418
constexpr auto GetLeft() const
Definition: rect.h:355
constexpr auto GetRight() const
Definition: rect.h:359
constexpr TPoint< T > GetLeftBottom() const
Definition: rect.h:371
constexpr TPoint< T > GetRightTop() const
Definition: rect.h:367
constexpr TPoint< T > GetRightBottom() const
Definition: rect.h:375
constexpr TPoint< T > GetLeftTop() const
Definition: rect.h:363
const size_t end