Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2017 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #ifndef SkVertices_DEFINED
      9 #define SkVertices_DEFINED
     10 
     11 #include "SkColor.h"
     12 #include "SkData.h"
     13 #include "SkPoint.h"
     14 #include "SkRect.h"
     15 #include "SkRefCnt.h"
     16 
     17 /**
     18  * An immutable set of vertex data that can be used with SkCanvas::drawVertices.
     19  */
     20 class SK_API SkVertices : public SkNVRefCnt<SkVertices> {
     21 public:
     22     // BoneIndices indicates which (of a maximum of 4 bones) a given vertex will interpolate
     23     // between. To indicate that a slot is not used, the convention is to assign the bone index
     24     // to 0.
     25     struct BoneIndices {
     26         uint32_t indices[4];
     27 
     28         uint32_t& operator[] (int i) {
     29             SkASSERT(i >= 0);
     30             SkASSERT(i < 4);
     31             return indices[i];
     32         }
     33 
     34         const uint32_t& operator[] (int i) const {
     35             SkASSERT(i >= 0);
     36             SkASSERT(i < 4);
     37             return indices[i];
     38         }
     39     };
     40 
     41     // BoneWeights stores the interpolation weight for each of the (maximum of 4) bones a given
     42     // vertex interpolates between. To indicate that a slot is not used, the weight for that
     43     // slot should be 0.
     44     struct BoneWeights {
     45         float weights[4];
     46 
     47         float& operator[] (int i) {
     48             SkASSERT(i >= 0);
     49             SkASSERT(i < 4);
     50             return weights[i];
     51         }
     52 
     53         const float& operator[] (int i) const {
     54             SkASSERT(i >= 0);
     55             SkASSERT(i < 4);
     56             return weights[i];
     57         }
     58     };
     59 
     60     // Bone stores a 3x2 transformation matrix in column major order:
     61     // | scaleX   skewX transX |
     62     // |  skewY  scaleY transY |
     63     // SkRSXform is insufficient because bones can have non uniform scale.
     64     struct Bone {
     65         float values[6];
     66 
     67         float& operator[] (int i) {
     68             SkASSERT(i >= 0);
     69             SkASSERT(i < 6);
     70             return values[i];
     71         }
     72 
     73         const float& operator[] (int i) const {
     74             SkASSERT(i >= 0);
     75             SkASSERT(i < 6);
     76             return values[i];
     77         }
     78 
     79         SkPoint mapPoint(const SkPoint& point) const {
     80             float x = values[0] * point.x() + values[2] * point.y() + values[4];
     81             float y = values[1] * point.x() + values[3] * point.y() + values[5];
     82             return SkPoint::Make(x, y);
     83         }
     84 
     85         SkRect mapRect(const SkRect& rect) const {
     86             SkRect dst = SkRect::MakeEmpty();
     87             SkPoint quad[4];
     88             rect.toQuad(quad);
     89             for (int i = 0; i < 4; i ++) {
     90                 quad[i] = mapPoint(quad[i]);
     91             }
     92             dst.setBoundsNoCheck(quad, 4);
     93             return dst;
     94         }
     95     };
     96 
     97     enum VertexMode {
     98         kTriangles_VertexMode,
     99         kTriangleStrip_VertexMode,
    100         kTriangleFan_VertexMode,
    101 
    102         kLast_VertexMode = kTriangleFan_VertexMode,
    103     };
    104 
    105     /**
    106      *  Create a vertices by copying the specified arrays. texs, colors, boneIndices, and
    107      *  boneWeights may be nullptr, and indices is ignored if indexCount == 0.
    108      *
    109      *  boneIndices and boneWeights must either both be nullptr or both point to valid data.
    110      *  If specified, they must both contain 'vertexCount' entries.
    111      */
    112     static sk_sp<SkVertices> MakeCopy(VertexMode mode, int vertexCount,
    113                                       const SkPoint positions[],
    114                                       const SkPoint texs[],
    115                                       const SkColor colors[],
    116                                       const BoneIndices boneIndices[],
    117                                       const BoneWeights boneWeights[],
    118                                       int indexCount,
    119                                       const uint16_t indices[],
    120                                       bool isVolatile = true);
    121 
    122     static sk_sp<SkVertices> MakeCopy(VertexMode mode, int vertexCount,
    123                                       const SkPoint positions[],
    124                                       const SkPoint texs[],
    125                                       const SkColor colors[],
    126                                       const BoneIndices boneIndices[],
    127                                       const BoneWeights boneWeights[],
    128                                       bool isVolatile = true) {
    129         return MakeCopy(mode,
    130                         vertexCount,
    131                         positions,
    132                         texs,
    133                         colors,
    134                         boneIndices,
    135                         boneWeights,
    136                         0,
    137                         nullptr,
    138                         isVolatile);
    139     }
    140 
    141     static sk_sp<SkVertices> MakeCopy(VertexMode mode, int vertexCount,
    142                                       const SkPoint positions[],
    143                                       const SkPoint texs[],
    144                                       const SkColor colors[],
    145                                       int indexCount,
    146                                       const uint16_t indices[],
    147                                       bool isVolatile = true) {
    148         return MakeCopy(mode,
    149                         vertexCount,
    150                         positions,
    151                         texs,
    152                         colors,
    153                         nullptr,
    154                         nullptr,
    155                         indexCount,
    156                         indices,
    157                         isVolatile);
    158     }
    159 
    160     static sk_sp<SkVertices> MakeCopy(VertexMode mode, int vertexCount,
    161                                       const SkPoint positions[],
    162                                       const SkPoint texs[],
    163                                       const SkColor colors[],
    164                                       bool isVolatile = true) {
    165         return MakeCopy(mode, vertexCount, positions, texs, colors, nullptr, nullptr, isVolatile);
    166     }
    167 
    168     struct Sizes;
    169 
    170     enum BuilderFlags {
    171         kHasTexCoords_BuilderFlag   = 1 << 0,
    172         kHasColors_BuilderFlag      = 1 << 1,
    173         kHasBones_BuilderFlag       = 1 << 2,
    174         kIsNonVolatile_BuilderFlag  = 1 << 3,
    175     };
    176     class Builder {
    177     public:
    178         Builder(VertexMode mode, int vertexCount, int indexCount, uint32_t flags);
    179 
    180         bool isValid() const { return fVertices != nullptr; }
    181 
    182         // if the builder is invalid, these will return 0
    183         int vertexCount() const;
    184         int indexCount() const;
    185         bool isVolatile() const;
    186         SkPoint* positions();
    187         SkPoint* texCoords();       // returns null if there are no texCoords
    188         SkColor* colors();          // returns null if there are no colors
    189         BoneIndices* boneIndices(); // returns null if there are no bone indices
    190         BoneWeights* boneWeights(); // returns null if there are no bone weights
    191         uint16_t* indices();        // returns null if there are no indices
    192 
    193         // Detach the built vertices object. After the first call, this will always return null.
    194         sk_sp<SkVertices> detach();
    195 
    196     private:
    197         Builder(VertexMode mode, int vertexCount, int indexCount, bool isVolatile, const Sizes&);
    198 
    199         void init(VertexMode mode, int vertexCount, int indexCount, bool isVolatile, const Sizes&);
    200 
    201         // holds a partially complete object. only completed in detach()
    202         sk_sp<SkVertices> fVertices;
    203         // Extra storage for intermediate vertices in the case where the client specifies indexed
    204         // triangle fans. These get converted to indexed triangles when the Builder is finalized.
    205         std::unique_ptr<uint8_t[]> fIntermediateFanIndices;
    206 
    207         friend class SkVertices;
    208     };
    209 
    210     uint32_t uniqueID() const { return fUniqueID; }
    211     VertexMode mode() const { return fMode; }
    212     const SkRect& bounds() const { return fBounds; }
    213 
    214     bool hasColors() const { return SkToBool(this->colors()); }
    215     bool hasTexCoords() const { return SkToBool(this->texCoords()); }
    216     bool hasBones() const { return SkToBool(this->boneIndices()); }
    217     bool hasIndices() const { return SkToBool(this->indices()); }
    218 
    219     int vertexCount() const { return fVertexCnt; }
    220     const SkPoint* positions() const { return fPositions; }
    221     const SkPoint* texCoords() const { return fTexs; }
    222     const SkColor* colors() const { return fColors; }
    223 
    224     const BoneIndices* boneIndices() const { return fBoneIndices; }
    225     const BoneWeights* boneWeights() const { return fBoneWeights; }
    226 
    227     int indexCount() const { return fIndexCnt; }
    228     const uint16_t* indices() const { return fIndices; }
    229 
    230     bool isVolatile() const { return fIsVolatile; }
    231 
    232     sk_sp<SkVertices> applyBones(const Bone bones[], int boneCount) const;
    233 
    234     // returns approximate byte size of the vertices object
    235     size_t approximateSize() const;
    236 
    237     /**
    238      *  Recreate a vertices from a buffer previously created by calling encode().
    239      *  Returns null if the data is corrupt or the length is incorrect for the contents.
    240      */
    241     static sk_sp<SkVertices> Decode(const void* buffer, size_t length);
    242 
    243     /**
    244      *  Pack the vertices object into a byte buffer. This can be used to recreate the vertices
    245      *  by calling Decode() with the buffer.
    246      */
    247     sk_sp<SkData> encode() const;
    248 
    249 private:
    250     SkVertices() {}
    251 
    252     // these are needed since we've manually sized our allocation (see Builder::init)
    253     friend class SkNVRefCnt<SkVertices>;
    254     void operator delete(void* p);
    255 
    256     static sk_sp<SkVertices> Alloc(int vCount, int iCount, uint32_t builderFlags,
    257                                    size_t* arraySize);
    258 
    259     // we store this first, to pair with the refcnt in our base-class, so we don't have an
    260     // unnecessary pad between it and the (possibly 8-byte aligned) ptrs.
    261     uint32_t fUniqueID;
    262 
    263     // these point inside our allocation, so none of these can be "freed"
    264     SkPoint*     fPositions;
    265     SkPoint*     fTexs;
    266     SkColor*     fColors;
    267     BoneIndices* fBoneIndices;
    268     BoneWeights* fBoneWeights;
    269     uint16_t*    fIndices;
    270 
    271     SkRect  fBounds;    // computed to be the union of the fPositions[]
    272     int     fVertexCnt;
    273     int     fIndexCnt;
    274 
    275     bool fIsVolatile;
    276 
    277     VertexMode fMode;
    278     // below here is where the actual array data is stored.
    279 };
    280 
    281 #endif
    282