Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 23e60b7

Browse files
committed
[Impeller] Add Rect::GetNormalizingTransform to handle UV coordinate conversion
1 parent a1bad07 commit 23e60b7

File tree

5 files changed

+185
-20
lines changed

5 files changed

+185
-20
lines changed

impeller/entity/geometry/fill_path_geometry.cc

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ GeometryResult FillPathGeometry::GetPositionUVBuffer(
8282
RenderPass& pass) {
8383
using VS = TextureFillVertexShader;
8484

85+
auto uv_transform =
86+
effect_transform * texture_coverage.GetNormalizingTransform();
87+
8588
if (path_.GetFillType() == FillType::kNonZero && //
8689
path_.IsConvex()) {
8790
auto [points, indices] = TessellateConvex(
@@ -93,9 +96,7 @@ GeometryResult FillPathGeometry::GetPositionUVBuffer(
9396
for (auto i = 0u; i < points.size(); i++) {
9497
VS::PerVertexData data;
9598
data.position = points[i];
96-
data.texture_coords = effect_transform *
97-
(points[i] - texture_coverage.origin) /
98-
texture_coverage.size;
99+
data.texture_coords = uv_transform * points[i];
99100
vertex_builder.AppendVertex(data);
100101
}
101102
for (auto i = 0u; i < indices.size(); i++) {
@@ -116,16 +117,14 @@ GeometryResult FillPathGeometry::GetPositionUVBuffer(
116117
auto tesselation_result = renderer.GetTessellator()->Tessellate(
117118
path_.GetFillType(),
118119
path_.CreatePolyline(entity.GetTransformation().GetMaxBasisLength()),
119-
[&vertex_builder, &texture_coverage, &effect_transform](
120+
[&vertex_builder, &uv_transform](
120121
const float* vertices, size_t vertices_count, const uint16_t* indices,
121122
size_t indices_count) {
122123
for (auto i = 0u; i < vertices_count * 2; i += 2) {
123124
VS::PerVertexData data;
124125
Point vtx = {vertices[i], vertices[i + 1]};
125126
data.position = vtx;
126-
data.texture_coords = effect_transform *
127-
(vtx - texture_coverage.origin) /
128-
texture_coverage.size;
127+
data.texture_coords = uv_transform * vtx;
129128
vertex_builder.AppendVertex(data);
130129
}
131130
FML_DCHECK(vertex_builder.GetVertexCount() == vertices_count);

impeller/entity/geometry/geometry.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,13 @@ GeometryResult ComputeUVGeometryForRect(Rect source_rect,
7575
RenderPass& pass) {
7676
auto& host_buffer = pass.GetTransientsBuffer();
7777

78+
auto uv_transform =
79+
effect_transform * texture_coverage.GetNormalizingTransform();
7880
std::vector<Point> data(8);
7981
auto points = source_rect.GetPoints();
8082
for (auto i = 0u, j = 0u; i < 8; i += 2, j++) {
8183
data[i] = points[j];
82-
data[i + 1] = effect_transform * (points[j] - texture_coverage.origin) /
83-
texture_coverage.size;
84+
data[i + 1] = uv_transform * points[j];
8485
}
8586

8687
return GeometryResult{

impeller/entity/geometry/vertices_geometry.cc

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -227,18 +227,16 @@ GeometryResult VerticesGeometry::GetPositionUVBuffer(
227227

228228
auto index_count = indices_.size();
229229
auto vertex_count = vertices_.size();
230-
auto size = texture_coverage.size;
231-
auto origin = texture_coverage.origin;
230+
auto uv_transform =
231+
effect_transform * texture_coverage.GetNormalizingTransform();
232232
auto has_texture_coordinates = HasTextureCoordinates();
233233
std::vector<VS::PerVertexData> vertex_data(vertex_count);
234234
{
235235
for (auto i = 0u; i < vertex_count; i++) {
236236
auto vertex = vertices_[i];
237237
auto texture_coord =
238238
has_texture_coordinates ? texture_coordinates_[i] : vertices_[i];
239-
auto uv =
240-
effect_transform * Point((texture_coord.x - origin.x) / size.width,
241-
(texture_coord.y - origin.y) / size.height);
239+
auto uv = uv_transform * texture_coord;
242240
// From experimentation we need to clamp these values to < 1.0 or else
243241
// there can be flickering.
244242
vertex_data[i] = {

impeller/geometry/rect.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,35 @@ struct TRect {
214214
return TRect::MakePointBounds(points.begin(), points.end()).value();
215215
}
216216

217+
/// @brief Constructs a Matrix that will map all points in the coordinate
218+
/// space of the rectangle into a new normalized coordinate space
219+
/// where the upper left corner of the rectangle maps to (0, 0)
220+
/// and the lower right corner of the rectangle maps to (1, 1).
221+
///
222+
/// Empty and non-finite rectangles will return a zero-scaling
223+
/// transform that maps all points to (0, 0).
224+
constexpr Matrix GetNormalizingTransform() const {
225+
if (!IsEmpty()) {
226+
Scalar sx = 1.0 / size.width;
227+
Scalar sy = 1.0 / size.height;
228+
Scalar tx = origin.x * -sx;
229+
Scalar ty = origin.y * -sy;
230+
231+
// Exclude NaN and infinities and either scale underflowing to zero
232+
if (sx != 0.0 && sy != 0.0 && 0.0 * sx * sy * tx * ty == 0.0) {
233+
// clang-format off
234+
return Matrix( sx, 0.0f, 0.0f, 0.0f,
235+
0.0f, sy, 0.0f, 0.0f,
236+
0.0f, 0.0f, 1.0f, 0.0f,
237+
tx, ty, 0.0f, 1.0f);
238+
// clang-format on
239+
}
240+
}
241+
242+
// Map all coordinates to the origin.
243+
return Matrix::MakeScale({0.0f, 0.0f, 1.0f});
244+
}
245+
217246
constexpr TRect Union(const TRect& o) const {
218247
auto this_ltrb = GetLTRB();
219248
auto other_ltrb = o.GetLTRB();

impeller/geometry/rect_unittests.cc

Lines changed: 144 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ namespace testing {
1414
TEST(RectTest, RectOriginSizeGetters) {
1515
{
1616
Rect r = Rect::MakeOriginSize({10, 20}, {50, 40});
17-
ASSERT_EQ(r.GetOrigin(), Point(10, 20));
18-
ASSERT_EQ(r.GetSize(), Size(50, 40));
17+
EXPECT_EQ(r.GetOrigin(), Point(10, 20));
18+
EXPECT_EQ(r.GetSize(), Size(50, 40));
1919
}
2020

2121
{
2222
Rect r = Rect::MakeLTRB(10, 20, 50, 40);
23-
ASSERT_EQ(r.GetOrigin(), Point(10, 20));
24-
ASSERT_EQ(r.GetSize(), Size(40, 20));
23+
EXPECT_EQ(r.GetOrigin(), Point(10, 20));
24+
EXPECT_EQ(r.GetSize(), Size(40, 20));
2525
}
2626
}
2727

@@ -44,14 +44,152 @@ TEST(RectTest, RectMakeSize) {
4444
Size s(100, 200);
4545
IRect r = IRect::MakeSize(s);
4646
IRect expected = IRect::MakeLTRB(0, 0, 100, 200);
47-
ASSERT_EQ(r, expected);
47+
EXPECT_EQ(r, expected);
4848
}
4949

5050
{
5151
ISize s(100, 200);
5252
IRect r = IRect::MakeSize(s);
5353
IRect expected = IRect::MakeLTRB(0, 0, 100, 200);
54-
ASSERT_EQ(r, expected);
54+
EXPECT_EQ(r, expected);
55+
}
56+
}
57+
58+
TEST(RectTest, RectGetNormalizingTransform) {
59+
{
60+
// Checks for expected matrix values
61+
62+
auto r = Rect::MakeXYWH(100, 200, 200, 400);
63+
64+
EXPECT_EQ(r.GetNormalizingTransform(),
65+
Matrix::MakeScale({0.005, 0.0025, 1.0}) *
66+
Matrix::MakeTranslation({-100, -200}));
67+
}
68+
69+
{
70+
// Checks for expected transformation of points relative to the rect
71+
72+
auto r = Rect::MakeLTRB(300, 500, 400, 700);
73+
auto m = r.GetNormalizingTransform();
74+
75+
// The 4 corners of the rect => (0, 0) to (1, 1)
76+
EXPECT_EQ(m * Point(300, 500), Point(0, 0));
77+
EXPECT_EQ(m * Point(400, 500), Point(1, 0));
78+
EXPECT_EQ(m * Point(400, 700), Point(1, 1));
79+
EXPECT_EQ(m * Point(300, 700), Point(0, 1));
80+
81+
// The center => (0.5, 0.5)
82+
EXPECT_EQ(m * Point(350, 600), Point(0.5, 0.5));
83+
84+
// Outside the 4 corners => (-1, -1) to (2, 2)
85+
EXPECT_EQ(m * Point(200, 300), Point(-1, -1));
86+
EXPECT_EQ(m * Point(500, 300), Point(2, -1));
87+
EXPECT_EQ(m * Point(500, 900), Point(2, 2));
88+
EXPECT_EQ(m * Point(200, 900), Point(-1, 2));
89+
}
90+
91+
{
92+
// Checks for behavior with empty rects
93+
94+
auto zero = Matrix::MakeScale({0.0, 0.0, 1.0});
95+
96+
// Empty for width and/or height == 0
97+
EXPECT_EQ(Rect::MakeXYWH(10, 10, 0, 10).GetNormalizingTransform(), zero);
98+
EXPECT_EQ(Rect::MakeXYWH(10, 10, 10, 0).GetNormalizingTransform(), zero);
99+
EXPECT_EQ(Rect::MakeXYWH(10, 10, 0, 0).GetNormalizingTransform(), zero);
100+
101+
// Empty for width and/or height < 0
102+
EXPECT_EQ(Rect::MakeXYWH(10, 10, -1, 10).GetNormalizingTransform(), zero);
103+
EXPECT_EQ(Rect::MakeXYWH(10, 10, 10, -1).GetNormalizingTransform(), zero);
104+
EXPECT_EQ(Rect::MakeXYWH(10, 10, -1, -1).GetNormalizingTransform(), zero);
105+
}
106+
107+
{
108+
// Checks for behavior with non-finite rects
109+
110+
auto z = Matrix::MakeScale({0.0, 0.0, 1.0});
111+
auto nan = std::numeric_limits<Scalar>::quiet_NaN();
112+
auto inf = std::numeric_limits<Scalar>::infinity();
113+
114+
// Non-finite for width and/or height == nan
115+
EXPECT_EQ(Rect::MakeXYWH(10, 10, nan, 10).GetNormalizingTransform(), z);
116+
EXPECT_EQ(Rect::MakeXYWH(10, 10, 10, nan).GetNormalizingTransform(), z);
117+
EXPECT_EQ(Rect::MakeXYWH(10, 10, nan, nan).GetNormalizingTransform(), z);
118+
119+
// Non-finite for width and/or height == inf
120+
EXPECT_EQ(Rect::MakeXYWH(10, 10, inf, 10).GetNormalizingTransform(), z);
121+
EXPECT_EQ(Rect::MakeXYWH(10, 10, 10, inf).GetNormalizingTransform(), z);
122+
EXPECT_EQ(Rect::MakeXYWH(10, 10, inf, inf).GetNormalizingTransform(), z);
123+
124+
// Non-finite for width and/or height == -inf
125+
EXPECT_EQ(Rect::MakeXYWH(10, 10, -inf, 10).GetNormalizingTransform(), z);
126+
EXPECT_EQ(Rect::MakeXYWH(10, 10, 10, -inf).GetNormalizingTransform(), z);
127+
EXPECT_EQ(Rect::MakeXYWH(10, 10, -inf, -inf).GetNormalizingTransform(), z);
128+
129+
// Non-finite for origin X and/or Y == nan
130+
EXPECT_EQ(Rect::MakeXYWH(nan, 10, 10, 10).GetNormalizingTransform(), z);
131+
EXPECT_EQ(Rect::MakeXYWH(10, nan, 10, 10).GetNormalizingTransform(), z);
132+
EXPECT_EQ(Rect::MakeXYWH(nan, nan, 10, 10).GetNormalizingTransform(), z);
133+
134+
// Non-finite for origin X and/or Y == inf
135+
EXPECT_EQ(Rect::MakeXYWH(inf, 10, 10, 10).GetNormalizingTransform(), z);
136+
EXPECT_EQ(Rect::MakeXYWH(10, inf, 10, 10).GetNormalizingTransform(), z);
137+
EXPECT_EQ(Rect::MakeXYWH(inf, inf, 10, 10).GetNormalizingTransform(), z);
138+
139+
// Non-finite for origin X and/or Y == -inf
140+
EXPECT_EQ(Rect::MakeXYWH(-inf, 10, 10, 10).GetNormalizingTransform(), z);
141+
EXPECT_EQ(Rect::MakeXYWH(10, -inf, 10, 10).GetNormalizingTransform(), z);
142+
EXPECT_EQ(Rect::MakeXYWH(-inf, -inf, 10, 10).GetNormalizingTransform(), z);
143+
}
144+
}
145+
146+
TEST(RectTest, IRectGetNormalizingTransform) {
147+
{
148+
// Checks for expected matrix values
149+
150+
auto r = IRect::MakeXYWH(100, 200, 200, 400);
151+
152+
EXPECT_EQ(r.GetNormalizingTransform(),
153+
Matrix::MakeScale({0.005, 0.0025, 1.0}) *
154+
Matrix::MakeTranslation({-100, -200}));
155+
}
156+
157+
{
158+
// Checks for expected transformation of points relative to the rect
159+
160+
auto r = IRect::MakeLTRB(300, 500, 400, 700);
161+
auto m = r.GetNormalizingTransform();
162+
163+
// The 4 corners of the rect => (0, 0) to (1, 1)
164+
EXPECT_EQ(m * Point(300, 500), Point(0, 0));
165+
EXPECT_EQ(m * Point(400, 500), Point(1, 0));
166+
EXPECT_EQ(m * Point(400, 700), Point(1, 1));
167+
EXPECT_EQ(m * Point(300, 700), Point(0, 1));
168+
169+
// The center => (0.5, 0.5)
170+
EXPECT_EQ(m * Point(350, 600), Point(0.5, 0.5));
171+
172+
// Outside the 4 corners => (-1, -1) to (2, 2)
173+
EXPECT_EQ(m * Point(200, 300), Point(-1, -1));
174+
EXPECT_EQ(m * Point(500, 300), Point(2, -1));
175+
EXPECT_EQ(m * Point(500, 900), Point(2, 2));
176+
EXPECT_EQ(m * Point(200, 900), Point(-1, 2));
177+
}
178+
179+
{
180+
// Checks for behavior with empty rects
181+
182+
auto zero = Matrix::MakeScale({0.0, 0.0, 1.0});
183+
184+
// Empty for width and/or height == 0
185+
EXPECT_EQ(IRect::MakeXYWH(10, 10, 0, 10).GetNormalizingTransform(), zero);
186+
EXPECT_EQ(IRect::MakeXYWH(10, 10, 10, 0).GetNormalizingTransform(), zero);
187+
EXPECT_EQ(IRect::MakeXYWH(10, 10, 0, 0).GetNormalizingTransform(), zero);
188+
189+
// Empty for width and/or height < 0
190+
EXPECT_EQ(IRect::MakeXYWH(10, 10, -1, 10).GetNormalizingTransform(), zero);
191+
EXPECT_EQ(IRect::MakeXYWH(10, 10, 10, -1).GetNormalizingTransform(), zero);
192+
EXPECT_EQ(IRect::MakeXYWH(10, 10, -1, -1).GetNormalizingTransform(), zero);
55193
}
56194
}
57195

0 commit comments

Comments
 (0)