Skip to content

Commit

Permalink
[tessellator]Expose and document smoothing approximation via the C/Da…
Browse files Browse the repository at this point in the history
…rt API. Minor refactor of tessellator to supply fill type to method rather than to object. (flutter#65)
  • Loading branch information
dnfield authored Mar 9, 2022
1 parent a02dd2e commit 42bea84
Show file tree
Hide file tree
Showing 12 changed files with 220 additions and 78 deletions.
13 changes: 7 additions & 6 deletions impeller/entity/contents/linear_gradient_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,13 @@ bool LinearGradientContents::Render(const ContentContext& renderer,

auto vertices_builder = VertexBufferBuilder<VS::PerVertexData>();
{
auto result = Tessellator{entity.GetPath().GetFillType()}.Tessellate(
entity.GetPath().CreatePolyline(), [&vertices_builder](Point point) {
VS::PerVertexData vtx;
vtx.vertices = point;
vertices_builder.AppendVertex(vtx);
});
auto result = Tessellator{}.Tessellate(entity.GetPath().GetFillType(),
entity.GetPath().CreatePolyline(),
[&vertices_builder](Point point) {
VS::PerVertexData vtx;
vtx.vertices = point;
vertices_builder.AppendVertex(vtx);
});
if (!result) {
return false;
}
Expand Down
4 changes: 2 additions & 2 deletions impeller/entity/contents/solid_color_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ VertexBuffer SolidColorContents::CreateSolidFillVertices(const Path& path,

VertexBufferBuilder<VS::PerVertexData> vtx_builder;

auto tesselation_result = Tessellator{path.GetFillType()}.Tessellate(
path.CreatePolyline(), [&vtx_builder](auto point) {
auto tesselation_result = Tessellator{}.Tessellate(
path.GetFillType(), path.CreatePolyline(), [&vtx_builder](auto point) {
VS::PerVertexData vtx;
vtx.vertices = point;
vtx_builder.AppendVertex(vtx);
Expand Down
3 changes: 2 additions & 1 deletion impeller/entity/contents/text_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ bool TextContents::Render(const ContentContext& renderer,
// atlas.
{
VertexBufferBuilder<VS::PerVertexData> vertex_builder;
if (!Tessellator{FillType::kPositive}.Tessellate(
if (!Tessellator{}.Tessellate(
FillType::kPositive,
PathBuilder{}
.AddRect(Rect::MakeXYWH(0.0, 0.0, 1.0, 1.0))
.TakePath()
Expand Down
25 changes: 12 additions & 13 deletions impeller/entity/contents/texture_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,18 @@ bool TextureContents::Render(const ContentContext& renderer,

VertexBufferBuilder<VS::PerVertexData> vertex_builder;
{
const auto tess_result =
Tessellator{entity.GetPath().GetFillType()}.Tessellate(
entity.GetPath().CreatePolyline(),
[this, &vertex_builder, &coverage_rect, &texture_size](Point vtx) {
VS::PerVertexData data;
data.vertices = vtx;
auto coverage_coords =
(vtx - coverage_rect->origin) / coverage_rect->size;
data.texture_coords =
(source_rect_.origin + source_rect_.size * coverage_coords) /
texture_size;
vertex_builder.AppendVertex(data);
});
const auto tess_result = Tessellator{}.Tessellate(
entity.GetPath().GetFillType(), entity.GetPath().CreatePolyline(),
[this, &vertex_builder, &coverage_rect, &texture_size](Point vtx) {
VS::PerVertexData data;
data.vertices = vtx;
auto coverage_coords =
(vtx - coverage_rect->origin) / coverage_rect->size;
data.texture_coords =
(source_rect_.origin + source_rect_.size * coverage_coords) /
texture_size;
vertex_builder.AppendVertex(data);
});
if (!tess_result) {
return false;
}
Expand Down
42 changes: 31 additions & 11 deletions impeller/entity/entity_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -502,10 +502,9 @@ TEST_F(EntityTest, BlendingModeOptions) {
// test GUI.

const Entity::BlendMode b{};
static_assert(
b == Entity::BlendMode::kClear); // Ensure the first item in
// the switch is the first
// item in the enum.
static_assert(b == Entity::BlendMode::kClear); // Ensure the first item in
// the switch is the first
// item in the enum.
switch (b) {
case Entity::BlendMode::kClear:
blend_mode_names.push_back("Clear");
Expand All @@ -521,8 +520,7 @@ TEST_F(EntityTest, BlendingModeOptions) {
blend_mode_values.push_back(Entity::BlendMode::kSourceOver);
case Entity::BlendMode::kDestinationOver:
blend_mode_names.push_back("DestinationOver");
blend_mode_values.push_back(
Entity::BlendMode::kDestinationOver);
blend_mode_values.push_back(Entity::BlendMode::kDestinationOver);
};
}

Expand All @@ -534,9 +532,8 @@ TEST_F(EntityTest, BlendingModeOptions) {
ImGui::SetNextWindowPos({200, 450});
}

auto draw_rect = [&context, &pass](
Rect rect, Color color,
Entity::BlendMode blend_mode) -> bool {
auto draw_rect = [&context, &pass](Rect rect, Color color,
Entity::BlendMode blend_mode) -> bool {
using VS = SolidFillPipeline::VertexShader;
VertexBufferBuilder<VS::PerVertexData> vtx_builder;
{
Expand Down Expand Up @@ -579,8 +576,7 @@ TEST_F(EntityTest, BlendingModeOptions) {
blend_mode_names.data(), blend_mode_names.size());
ImGui::End();

Entity::BlendMode selected_mode =
blend_mode_values[current_blend_index];
Entity::BlendMode selected_mode = blend_mode_values[current_blend_index];

Point a, b, c, d;
std::tie(a, b) = IMPELLER_PLAYGROUND_LINE(
Expand All @@ -601,5 +597,29 @@ TEST_F(EntityTest, BlendingModeOptions) {
ASSERT_TRUE(OpenPlaygroundHere(callback));
}

TEST_F(EntityTest, BezierCircleScaled) {
Entity entity;
auto path = PathBuilder{}
.MoveTo({97.325, 34.818})
.CubicCurveTo({98.50862885295136, 34.81812293973836},
{99.46822048142015, 33.85863261475589},
{99.46822048142015, 32.67499810206613})
.CubicCurveTo({99.46822048142015, 31.491363589376355},
{98.50862885295136, 30.53187326439389},
{97.32499434685802, 30.531998226542708})
.CubicCurveTo({96.14153655073771, 30.532123170035373},
{95.18222070648729, 31.491540299350355},
{95.18222070648729, 32.67499810206613})
.CubicCurveTo({95.18222070648729, 33.85845590478189},
{96.14153655073771, 34.81787303409686},
{97.32499434685802, 34.81799797758954})
.Close()
.TakePath();
entity.SetPath(path);
entity.SetTransformation(Matrix::MakeScale({20.0, 20.0, 1.0}).Translate({-80, -15, 0}));
entity.SetContents(SolidColorContents::Make(Color::Red()));
ASSERT_TRUE(OpenPlaygroundHere(entity));
}

} // namespace testing
} // namespace impeller
2 changes: 1 addition & 1 deletion impeller/geometry/path_component.cc
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ Point CubicPathComponent::SolveDerivative(Scalar time) const {

/*
* Paul de Casteljau's subdivision with modifications as described in
* http://www.antigrain.com/research/adaptive_bezier/index.html.
* http://agg.sourceforge.net/antigrain.com/research/adaptive_bezier/index.html.
* Refer to the diagram on that page for a description of the points.
*/
static void CubicPathSmoothenRecursive(const SmoothingApproximation& approx,
Expand Down
21 changes: 21 additions & 0 deletions impeller/geometry/path_component.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,31 @@

namespace impeller {

/// Information about how to approximate points on a curved path segment.
///
/// In particular, the values in this object control how many vertices to
/// generate when approximating curves, and what tolerances to use when
/// calculating the sharpness of curves.
struct SmoothingApproximation {
/// The scaling coefficient to use when translating to screen coordinates.
///
/// Values approaching 0.0 will generate smoother looking curves with a
/// greater number of vertices, and will be more expensive to calculate.
Scalar scale;

/// The tolerance value in radians for calculating sharp angles.
///
/// Values approaching 0.0 will provide more accurate approximation of sharp
/// turns. A 0.0 value means angle conditions are not considered at all.
Scalar angle_tolerance;

/// An angle in radians at which to introduce bevel cuts.
///
/// Values greater than zero will restirct the sharpness of bevel cuts on
/// turns.
Scalar cusp_limit;

/// Used to more quickly detect colinear cases.
Scalar distance_tolerance_square;

SmoothingApproximation(/* default */)
Expand Down
21 changes: 13 additions & 8 deletions impeller/tessellator/c/tessellator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,21 @@ void Close(PathBuilder* builder) {
builder->Close();
}

struct Vertices* Tessellate(PathBuilder* builder) {
auto path = builder->CopyPath();
auto polyline = path.CreatePolyline();
struct Vertices* Tessellate(PathBuilder* builder,
int fill_type,
Scalar scale,
Scalar angle_tolerance,
Scalar cusp_limit) {
auto path = builder->CopyPath(static_cast<FillType>(fill_type));
auto smoothing = SmoothingApproximation(scale, angle_tolerance, cusp_limit);
auto polyline = path.CreatePolyline(smoothing);

std::vector<float> points;
if (!Tessellator{path.GetFillType()}.Tessellate(polyline,
[&points](Point vertex) {
points.push_back(vertex.x);
points.push_back(vertex.y);
})) {
if (!Tessellator{}.Tessellate(path.GetFillType(), polyline,
[&points](Point vertex) {
points.push_back(vertex.x);
points.push_back(vertex.y);
})) {
return nullptr;
}

Expand Down
10 changes: 9 additions & 1 deletion impeller/tessellator/c/tessellator.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
#include "impeller/geometry/path_builder.h"
#include "impeller/tessellator/tessellator.h"

#ifdef _WIN32
#define IMPELLER_API __declspec(dllexport)
#else
#define IMPELLER_API __attribute__((visibility("default")))
#endif

extern "C" {

Expand Down Expand Up @@ -36,7 +40,11 @@ IMPELLER_API void CubicTo(PathBuilder* builder,

IMPELLER_API void Close(PathBuilder* builder);

IMPELLER_API struct Vertices* Tessellate(PathBuilder* builder);
IMPELLER_API struct Vertices* Tessellate(PathBuilder* builder,
int fill_type,
Scalar scale,
Scalar angle_tolerance,
Scalar cusp_limit);

IMPELLER_API void DestroyVertices(Vertices* vertices);

Expand Down
Loading

0 comments on commit 42bea84

Please sign in to comment.