text: // 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.
  
  #ifndef FLUTTER_DISPLAY_LIST_DISPLAY_LIST_VERTICES_H_
  #define FLUTTER_DISPLAY_LIST_DISPLAY_LIST_VERTICES_H_
  
  #include "flutter/display_list/types.h"
  
  namespace flutter {
  
  //------------------------------------------------------------------------------
  /// @brief      Defines the way in which the vertices of a DlVertices object
  ///             are separated into triangles into which to render.
  ///
  enum class DlVertexMode {
    /// The vertices are taken 3 at a time to form a triangle.
    kTriangles,
  
    /// The vertices are taken in overlapping triplets to form triangles, with
    /// each triplet sharing 2 of its vertices with the preceding and following
    /// triplets.
    /// vertices [ABCDE] yield 3 triangles ABC,BCD,CDE
    kTriangleStrip,
  
    /// The vertices are taken in overlapping pairs and combined with the first
    /// vertex to form triangles that radiate outward from the initial point.
    /// vertices [ABCDE] yield 3 triangles ABC,ACD,ADE
    kTriangleFan,
  };
  
  inline SkVertices::VertexMode ToSk(DlVertexMode dl_mode) {
    return static_cast<SkVertices::VertexMode>(dl_mode);
  }
  
  inline DlVertexMode ToDl(SkVertices::VertexMode sk_mode) {
    return static_cast<DlVertexMode>(sk_mode);
  }
  
  //------------------------------------------------------------------------------
  /// @brief      Holds all of the data (both required and optional) for a
  ///             DisplayList drawVertices call.
  ///
  /// There are 4 main pices of data:
  ///   - vertices():
  ///       the points on the rendering surface that define the pixels
  ///       being rendered to in a series of triangles. These points
  ///       can map to triangles in various ways depending on the
  ///       supplied |DlVertexMode|.
  ///   - texture_coordinates():
  ///       the points in the DlColorSource to map to the coordinates
  ///       of the triangles in the vertices(). If missing, the
  ///       vertex coordinates themselves will be used to map the
  ///       source colors to the vertices.
  ///   - colors():
  ///       colors to map to each triangle vertex. Note that each
  ///       vertex is mapped to exactly 1 color even if the DlVertex
  ///   - indices():
  ///       An indirection based on indices into the array of vertices
  ///       (and by extension, their associated texture_coordinates and
  ///       colors). Note that the DLVertexMode will still apply to the
  ///       indices in the same way (and instead of the way) that it
  ///       would normally be applied to the vertices themselves. The
  ///       indices are useful, for example, to fill the vertices with
  ///       a grid of points and then use the indices to define a
  ///       triangular mesh that covers that grid without having to
  ///       repeat the vertex (and texture coordinate and color)
  ///       information for the times when a given grid coordinate
  ///       gets reused in up to 4 mesh triangles.
  ///
  /// Note that each vertex is mapped to exactly 1 texture_coordinate and
  /// color even if the DlVertexMode or indices specify that it contributes
  /// to more than one output triangle.
  ///
  class DlVertices {
   public:
    /// @brief     A utility class to build up a |DlVertices| object
    ///            one set of data at a time.
    class Builder {
     public:
      /// @brief     flags to indicate/promise which of the optional
      ///            texture coordinates or colors will be supplied
      ///            during the build phase.
      union Flags {
        struct {
          unsigned has_texture_coordinates : 1;
          unsigned has_colors : 1;
        };
        uint32_t mask = 0;
  
        inline Flags operator|(const Flags& rhs) const {
          return {.mask = (mask | rhs.mask)};
        }
  
        inline Flags& operator|=(const Flags& rhs) {
          mask = mask | rhs.mask;
          return *this;
        }
      };
      static constexpr Flags kNone = {{false, false}};
      static constexpr Flags kHasTextureCoordinates = {{true, false}};
      static constexpr Flags kHasColors = {{false, true}};
  
      //--------------------------------------------------------------------------
      /// @brief     Constructs a Builder and prepares room for the
      ///            required and optional data.
      ///
      /// Vertices are always required. Optional texture coordinates
      /// and optional colors are reserved depending on the |Flags|.
      /// Optional indices will be reserved iff the index_count is
      /// positive (>0).
      ///
      /// The caller must provide all data that is promised by the
      /// supplied |flags| and |index_count| parameters before
      /// calling the |build()| method.
      Builder(DlVertexMode mode, int vertex_count, Flags flags, int index_count);
  
      /// Returns true iff the underlying object was successfully allocated.
      bool is_valid() { return vertices_ != nullptr; }
  
      /// @brief Copies the indicated list of points as vertices.
      ///
      /// fails if vertices have already been supplied.
      void store_vertices(const SkPoint points[]);
  
      /// @brief Copies the indicated list of float pairs as vertices.
      ///
      /// fails if vertices have already been supplied.
      void store_vertices(const float coordinates[]);
  
      /// @brief Copies the indicated list of points as texture coordinates.
      ///
      /// fails if texture coordinates have already been supplied or if they
      /// were not promised by the flags.has_texture_coordinates.
      void store_texture_coordinates(const SkPoint points[]);
  
      /// @brief Copies the indicated list of float pairs as texture coordinates.
      ///
      /// fails if texture coordinates have already been supplied or if they
      /// were not promised by the flags.has_texture_coordinates.
      void store_texture_coordinates(const float coordinates[]);
  
      /// @brief Copies the indicated list of colors as vertex colors.
      ///
      /// fails if colors have already been supplied or if they were not
      /// promised by the flags.has_colors.
      void store_colors(const SkColor colors[]);
  
      /// @brief Copies the indicated list of 16-bit indices as vertex indices.
      ///
      /// fails if indices have already been supplied or if they were not
      /// promised by (index_count > 0).
      void store_indices(const uint16_t indices[]);
  
      /// @brief Finalizes and the constructed DlVertices object.
      ///
      /// fails if any of the optional data promised in the constructor is
      /// missing.
      std::shared_ptr<DlVertices> build();
  
     private:
      std::shared_ptr<DlVertices> vertices_;
      bool needs_vertices_;
      bool needs_texture_coords_;
      bool needs_colors_;
      bool needs_indices_;
    };
  
    //--------------------------------------------------------------------------
    /// @brief     Constructs a DlVector with compact inline storage for all
    ///            of its required and optional lists of data.
    ///
    /// Vertices are always required. Optional texture coordinates
    /// and optional colors are stored if the arguments are non-null.
    /// Optional indices will be stored iff the array argument is
    /// non-null and the index_count is positive (>0).
    static std::shared_ptr<DlVertices> Make(DlVertexMode mode,
                                            int vertex_count,
                                            const SkPoint vertices[],
                                            const SkPoint texture_coordinates[],
                                            const SkColor colors[],
                                            int index_count = 0,
                                            const uint16_t indices[] = nullptr);
  
    /// Returns the size of the object including all of the inlined data.
    size_t size() const;
  
    /// Returns the bounds of the vertices.
    SkRect bounds() const { return bounds_; }
  
    /// Returns the vertex mode that defines how the vertices (or the indices)
    /// are turned into triangles.
    DlVertexMode mode() const { return mode_; }
  
    /// Returns the number of vertices, which also applies to the number of
    /// texture coordinate and colors if they are provided.
    int vertex_count() const { return vertex_count_; }
  
    /// Returns a pointer to the vertex information. Should be non-null.
    const SkPoint* vertices() const {
      return static_cast<const SkPoint*>(pod(vertices_offset_));
    }
  
    /// Returns a pointer to the vertex texture coordinate
    /// or null if none were provided.
    const SkPoint* texture_coordinates() const {
      return static_cast<const SkPoint*>(pod(texture_coordinates_offset_));
    }
  
    /// Returns a pointer to the vertex colors
    /// or null if none were provided.
    const SkColor* colors() const {
      return static_cast<const SkColor*>(pod(colors_offset_));
    }
  
    /// Returns a pointer to the count of vertex indices
    /// or 0 if none were provided.
    int index_count() const { return index_count_; }
  
    /// Returns a pointer to the vertex indices
    /// or null if none were provided.
    const uint16_t* indices() const {
      return static_cast<const uint16_t*>(pod(indices_offset_));
    }
  
    // Returns an equivalent sk_sp<SkVertices> analog to this object.
    sk_sp<SkVertices> skia_object() const;
  
    bool operator==(DlVertices const& other) const;
  
    bool operator!=(DlVertices const& other) const { return !(*this == other); }
  
   private:
    // Constructors are designed to encapsulate arrays sequentially in memory
    // which means they can only be called by intantiations that use the
    // new (ptr) paradigm which precomputes and preallocates the memory for
    // the class body and all of its arrays, such as in Builder.
    DlVertices(DlVertexMode mode,
               int vertex_count,
               const SkPoint vertices[],
               const SkPoint texture_coordinates[],
               const SkColor colors[],
               int index_count,
               const uint16_t indices[],
               const SkRect* bounds = nullptr);
  
    // This constructor is specifically used by the DlVertices::Builder to
    // establish the object before the copying of data is requested.
    DlVertices(DlVertexMode mode,
               int vertex_count,
               Builder::Flags flags,
               int index_count);
  
    // The copy constructor has the same memory pre-allocation requirements
    // as this other constructors. This particular version is used by the
    // DisplaylistBuilder to copy the instance into pre-allocated pod memory
    // in the display list buffer.
    explicit DlVertices(const DlVertices* other);
  
    DlVertexMode mode_;
  
    int vertex_count_;
    size_t vertices_offset_;
    size_t texture_coordinates_offset_;
    size_t colors_offset_;
  
    int index_count_;
    size_t indices_offset_;
  
    SkRect bounds_;
  
    const void* pod(int offset) const {
      if (offset <= 0) {
        return nullptr;
      }
      const void* base = static_cast<const void*>(this);
      return static_cast<const char*>(base) + offset;
    }
  
    friend class DisplayListBuilder;
  };
  
  }  // namespace flutter
  
  #endif  // FLUTTER_DISPLAY_LIST_DISPLAY_LIST_VERTICES_H_
  