Flutter Impeller
solid_rsuperellipse_blur_contents.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 #include <optional>
7 
15 
16 namespace impeller {
17 
18 namespace {
19 Vector3 Concat3(Size a, Scalar b) {
20  return {a.width, a.height, b};
21 }
22 } // namespace
23 
25 
27 
28 bool SolidRSuperellipseBlurContents::SetPassInfo(
29  RenderPass& pass,
30  const ContentContext& renderer,
31  PassContext& pass_context) const {
33 
34  FS::FragInfo frag_info;
35  frag_info.color = GetColor();
36  frag_info.center_adjust = Concat(pass_context.center, pass_context.adjust);
37  frag_info.r1_exponent_exponentInv =
38  Vector3(pass_context.r1, pass_context.exponent, pass_context.exponentInv);
39  frag_info.sInv_minEdge_scale =
40  Vector3(pass_context.sInv, pass_context.minEdge, pass_context.scale);
41 
42  // Additional math for RSuperellipse. See the frag file for explanation.
43  Scalar radius = GetCornerRadius();
44  Rect rect = GetRect();
45  RoundSuperellipseParam param =
47 
48  // Avoid 0-division error when radius is 0.
49  Scalar retractionDepth = fmax(radius, 0.001);
50 
51  frag_info.halfAxes_retractionDepth =
52  Concat3(rect.GetSize() / 2, retractionDepth);
53 
54  auto compute_info = [radius](RoundSuperellipseParam::Octant& octant) {
55  if (octant.se_n < 1) { // A rectangular corner
56  // Use a large split_radian, which is equivalent to kPiOver4 but avoids
57  // floating errors.
58  const Scalar kLargeSplitRadian = kPiOver2;
59  const Scalar kReallyLargeN = 1e10;
60  return Vector4(kLargeSplitRadian, 0, kReallyLargeN, -1.0 / kReallyLargeN);
61  }
62  Scalar n = octant.se_n;
63  Point split_point = Point(octant.se_a - radius, octant.se_a);
64  Scalar split_radian = std::atan2(split_point.x, split_point.y);
65  Scalar split_retraction =
66  (1 - pow(1 + pow(tan(split_radian), n), -1.0 / n)) * octant.se_a;
67  return Vector4(split_radian, split_retraction, n, -1.0 / n);
68  };
69  frag_info.infoTop = compute_info(param.top_right.top);
70  frag_info.infoRight = compute_info(param.top_right.right);
71 
72  auto compute_poly = [radius](RoundSuperellipseParam::Octant& octant) {
73  // Imperical formula that decreases the initial slope as the a/r ratio
74  // increases.
75  Scalar v0 = radius / octant.se_a * 3;
76  // A polynomial that satisfies f(0) = 1, f'(0) = v0, f(1) = 0, f'(1) = 0
77  return Vector4(v0 + 2.0, -2.0 * v0 - 3.0, v0, 1.0);
78  };
79  frag_info.polyTop = compute_poly(param.top_right.top);
80  frag_info.polyRight = compute_poly(param.top_right.right);
81 
82  // Back to pass setup.
83  auto& host_buffer = renderer.GetTransientsBuffer();
84  pass.SetCommandLabel("RSuperellipse Shadow");
85  pass.SetPipeline(renderer.GetRSuperellipseBlurPipeline(pass_context.opts));
86 
87  FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
88  return true;
89 }
90 
91 } // namespace impeller
FragmentShader_ FragmentShader
Definition: pipeline.h:164
static Vector4 Concat(Vector2 &a, Vector2 &b)
float Scalar
Definition: scalar.h:19
TRect< Scalar > Rect
Definition: rect.h:792
TPoint< Scalar > Point
Definition: point.h:327
LinePipeline::FragmentShader FS
constexpr float kPiOver2
Definition: constants.h:32
TSize< Scalar > Size
Definition: size.h:159
static RoundSuperellipseParam MakeBoundsRadius(const Rect &bounds, Scalar radius)