blob: 7c3ed34253713fa2c4a80dda52ef512bcfcd6056 [file] [log] [blame]
// 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 <memory>
#include "flutter/display_list/dl_color.h"
#include "third_party/skia/include/core/SkRect.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,
};
//------------------------------------------------------------------------------
/// @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 if 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 DlColor colors[]);
/// @brief Copies the indicated list of unsigned ints as vertex colors
/// in the 32-bit RGBA format.
///
/// fails if colors have already been supplied or if they were not
/// promised by the flags.has_colors.
void store_colors(const uint32_t colors[]) {
store_colors(reinterpret_cast<const DlColor*>(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 DlColor 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 DlColor* colors() const {
return static_cast<const DlColor*>(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_));
}
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 DlColor 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_