| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #pragma once |
| |
| #include <functional> |
| #include <vector> |
| |
| #include "flutter/impeller/geometry/matrix.h" |
| #include "flutter/impeller/geometry/point.h" |
| #include "flutter/impeller/geometry/scalar.h" |
| #include "flutter/impeller/geometry/trig.h" |
| #include "flutter/impeller/tessellator/tessellator.h" |
| |
| namespace impeller { |
| |
| using TessellatedPointProc = std::function<void(const Point& p)>; |
| |
| /// @brief A utility class to compute the number of divisions for a circle |
| /// given a transform-adjusted pixel radius and methods for generating |
| /// a tessellated set of triangles for a quarter or full circle. |
| /// |
| /// The constructor will compute the device pixel radius size for |
| /// the specified geometry-space |radius| when viewed under |
| /// a specified geometry-to-device |transform|. |
| /// |
| /// The object should be constructed with the expected transform and |
| /// radius of the circle, but can then be used to generate a triangular |
| /// tessellation with the computed number of divisions for any |
| /// radius after that. Since the coordinate space in which the |
| /// circle being tessellated is not necessarily device pixel space, |
| /// the radius supplied during tessellation might not match the |
| /// pixel radius computed during construction, but the two values |
| /// should be related by the transform in place when the tessellated |
| /// triangles are rendered for maximum tessellation fidelity. |
| class CircleTessellator { |
| public: |
| /// @brief The pixel tolerance used by the algorighm to determine how |
| /// many divisions to create for a circle. |
| /// |
| /// No point on the polygon of vertices should deviate from the |
| /// true circle by more than this tolerance. |
| static constexpr Scalar kCircleTolerance = 0.1; |
| |
| /// @brief Constructs a CircleTessellator that produces enough segments |
| /// to reasonably approximate a circle with a specified |radius| |
| /// when viewed under the specified |transform|. |
| CircleTessellator(std::shared_ptr<Tessellator>& tessellator, |
| const Matrix& transform, |
| Scalar radius) |
| : CircleTessellator(tessellator, transform.GetMaxBasisLength() * radius) { |
| } |
| |
| ~CircleTessellator() = default; |
| |
| /// @brief Return the number of divisions computed by the algorithm for |
| /// a single quarter circle. |
| size_t GetQuadrantDivisionCount() const { return trigs_.size() - 1; } |
| |
| /// @brief Return the number of vertices that will be generated to |
| /// tessellate a full circle with a triangle strip. |
| /// |
| /// This value can be used to pre-allocate space in a vector |
| /// to hold the vertices that will be produced by the |
| /// |GenerateCircleTriangleStrip| and |
| /// |GenerateRoundCapLineTriangleStrip| methods. |
| size_t GetCircleVertexCount() const { return trigs_.size() * 4; } |
| |
| /// @brief Generate the vertices for a triangle strip that covers the |
| /// circle at a given |radius| from a given |center|, delivering |
| /// the computed coordinates to the supplied |proc|. |
| /// |
| /// This procedure will generate no more than the number of |
| /// vertices returned by |GetCircleVertexCount| in an order |
| /// appropriate for rendering as a triangle strip. |
| void GenerateCircleTriangleStrip(const TessellatedPointProc& proc, |
| const Point& center, |
| Scalar radius) const; |
| |
| /// @brief Generate the vertices for a triangle strip that covers the |
| /// line from |p0| to |p1| with round caps of the specified |
| /// |radius|, delivering the computed coordinates to the supplied |
| /// |proc|. |
| /// |
| /// This procedure will generate no more than the number of |
| /// vertices returned by |GetCircleVertexCount| in an order |
| /// appropriate for rendering as a triangle strip. |
| void GenerateRoundCapLineTriangleStrip(const TessellatedPointProc& proc, |
| const Point& p0, |
| const Point& p1, |
| Scalar radius) const; |
| |
| private: |
| const std::vector<Trig>& trigs_; |
| std::vector<Trig> temp_trigs_; |
| |
| /// @brief Constructs a CircleTessellator that produces enough segments |
| /// to reasonably approximate a circle with a specified radius |
| /// in pixels. |
| explicit CircleTessellator(std::shared_ptr<Tessellator>& tessellator, |
| Scalar pixel_radius) |
| : trigs_(GetTrigsForDivisions(tessellator, |
| ComputeQuadrantDivisions(pixel_radius))) {} |
| |
| CircleTessellator(const CircleTessellator&) = delete; |
| |
| CircleTessellator& operator=(const CircleTessellator&) = delete; |
| |
| /// @brief Compute the number of vertices to divide each quadrant of |
| /// the circle into based on the expected pixel space radius. |
| /// |
| /// @return the number of vertices. |
| static size_t ComputeQuadrantDivisions(Scalar pixel_radius); |
| |
| /// @brief Compute the sine and cosine for each angle in the number of |
| /// divisions [0, divisions] of a quarter circle and return the |
| /// values in a vector of trig objects. |
| /// |
| /// Note that since the 0th division is included, the vector will |
| /// contain (divisions + 1) values. |
| /// |
| /// @return The vector of (divisions + 1) trig values. |
| const std::vector<Trig>& GetTrigsForDivisions( |
| std::shared_ptr<Tessellator>& tessellator, |
| size_t divisions); |
| |
| static constexpr int kPrecomputedDivisionCount = 1024; |
| static int kPrecomputedDivisions[kPrecomputedDivisionCount]; |
| }; |
| |
| } // namespace impeller |