aboutsummaryrefslogtreecommitdiffhomepage
path: root/include/core/SkVertices.h
blob: 9c1300b0a541c3ea1e4243862e900071640c8b7f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/*
 * Copyright 2017 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef SkVertices_DEFINED
#define SkVertices_DEFINED

#include "SkColor.h"
#include "SkData.h"
#include "SkPoint.h"
#include "SkRect.h"
#include "SkRefCnt.h"

/**
 * An immutable set of vertex data that can be used with SkCanvas::drawVertices.
 */
class SK_API SkVertices : public SkNVRefCnt<SkVertices> {
public:
    // BoneIndices indicates which (of a maximum of 4 bones) a given vertex will interpolate
    // between. To indicate that a slot is not used, the convention is to assign the bone index
    // to 0.
    struct BoneIndices {
        uint32_t indices[4];
    };

    // BoneWeights stores the interpolation weight for each of the (maximum of 4) bones a given
    // vertex interpolates between. To indicate that a slot is not used, the weight for that
    // slot should be 0.
    struct BoneWeights {
        float weights[4];
    };

    enum VertexMode {
        kTriangles_VertexMode,
        kTriangleStrip_VertexMode,
        kTriangleFan_VertexMode,

        kLast_VertexMode = kTriangleFan_VertexMode,
    };

    /**
     *  Create a vertices by copying the specified arrays. texs, colors, boneIndices, and
     *  boneWeights may be nullptr, and indices is ignored if indexCount == 0.
     *
     *  boneIndices and boneWeights must either both be nullptr or both point to valid data.
     *  If specified, they must both contain 'vertexCount' entries.
     */
    static sk_sp<SkVertices> MakeCopy(VertexMode mode, int vertexCount,
                                      const SkPoint positions[],
                                      const SkPoint texs[],
                                      const SkColor colors[],
                                      const BoneIndices boneIndices[],
                                      const BoneWeights boneWeights[],
                                      int indexCount,
                                      const uint16_t indices[],
                                      bool isVolatile = true);

    static sk_sp<SkVertices> MakeCopy(VertexMode mode, int vertexCount,
                                      const SkPoint positions[],
                                      const SkPoint texs[],
                                      const SkColor colors[],
                                      const BoneIndices boneIndices[],
                                      const BoneWeights boneWeights[],
                                      bool isVolatile = true) {
        return MakeCopy(mode,
                        vertexCount,
                        positions,
                        texs,
                        colors,
                        boneIndices,
                        boneWeights,
                        0,
                        nullptr,
                        isVolatile);
    }

    static sk_sp<SkVertices> MakeCopy(VertexMode mode, int vertexCount,
                                      const SkPoint positions[],
                                      const SkPoint texs[],
                                      const SkColor colors[],
                                      int indexCount,
                                      const uint16_t indices[],
                                      bool isVolatile = true) {
        return MakeCopy(mode,
                        vertexCount,
                        positions,
                        texs,
                        colors,
                        nullptr,
                        nullptr,
                        indexCount,
                        indices,
                        isVolatile);
    }

    static sk_sp<SkVertices> MakeCopy(VertexMode mode, int vertexCount,
                                      const SkPoint positions[],
                                      const SkPoint texs[],
                                      const SkColor colors[],
                                      bool isVolatile = true) {
        return MakeCopy(mode, vertexCount, positions, texs, colors, nullptr, nullptr, isVolatile);
    }

    struct Sizes;

    enum BuilderFlags {
        kHasTexCoords_BuilderFlag   = 1 << 0,
        kHasColors_BuilderFlag      = 1 << 1,
        kHasBones_BuilderFlag       = 1 << 2,
        kIsNonVolatile_BuilderFlag  = 1 << 3,
    };
    class Builder {
    public:
        Builder(VertexMode mode, int vertexCount, int indexCount, uint32_t flags);

        bool isValid() const { return fVertices != nullptr; }

        // if the builder is invalid, these will return 0
        int vertexCount() const;
        int indexCount() const;
        bool isVolatile() const;
        SkPoint* positions();
        SkPoint* texCoords();       // returns null if there are no texCoords
        SkColor* colors();          // returns null if there are no colors
        BoneIndices* boneIndices(); // returns null if there are no bone indices
        BoneWeights* boneWeights(); // returns null if there are no bone weights
        uint16_t* indices();        // returns null if there are no indices

        // Detach the built vertices object. After the first call, this will always return null.
        sk_sp<SkVertices> detach();

    private:
        Builder(VertexMode mode, int vertexCount, int indexCount, bool isVolatile, const Sizes&);

        void init(VertexMode mode, int vertexCount, int indexCount, bool isVolatile, const Sizes&);

        // holds a partially complete object. only completed in detach()
        sk_sp<SkVertices> fVertices;
        // Extra storage for intermediate vertices in the case where the client specifies indexed
        // triangle fans. These get converted to indexed triangles when the Builder is finalized.
        std::unique_ptr<uint8_t[]> fIntermediateFanIndices;

        friend class SkVertices;
    };

    uint32_t uniqueID() const { return fUniqueID; }
    VertexMode mode() const { return fMode; }
    const SkRect& bounds() const { return fBounds; }

    bool hasColors() const { return SkToBool(this->colors()); }
    bool hasTexCoords() const { return SkToBool(this->texCoords()); }
    bool hasBones() const { return SkToBool(this->boneIndices()); }
    bool hasIndices() const { return SkToBool(this->indices()); }

    int vertexCount() const { return fVertexCnt; }
    const SkPoint* positions() const { return fPositions; }
    const SkPoint* texCoords() const { return fTexs; }
    const SkColor* colors() const { return fColors; }

    const BoneIndices* boneIndices() const { return fBoneIndices; }
    const BoneWeights* boneWeights() const { return fBoneWeights; }

    int indexCount() const { return fIndexCnt; }
    const uint16_t* indices() const { return fIndices; }

    bool isVolatile() const { return fIsVolatile; }

    // returns approximate byte size of the vertices object
    size_t approximateSize() const;

    /**
     *  Recreate a vertices from a buffer previously created by calling encode().
     *  Returns null if the data is corrupt or the length is incorrect for the contents.
     */
    static sk_sp<SkVertices> Decode(const void* buffer, size_t length);

    /**
     *  Pack the vertices object into a byte buffer. This can be used to recreate the vertices
     *  by calling Decode() with the buffer.
     */
    sk_sp<SkData> encode() const;

private:
    SkVertices() {}

    // these are needed since we've manually sized our allocation (see Builder::init)
    friend class SkNVRefCnt<SkVertices>;
    void operator delete(void* p);

    static sk_sp<SkVertices> Alloc(int vCount, int iCount, uint32_t builderFlags,
                                   size_t* arraySize);

    // we store this first, to pair with the refcnt in our base-class, so we don't have an
    // unnecessary pad between it and the (possibly 8-byte aligned) ptrs.
    uint32_t fUniqueID;

    // these point inside our allocation, so none of these can be "freed"
    SkPoint*     fPositions;
    SkPoint*     fTexs;
    SkColor*     fColors;
    BoneIndices* fBoneIndices;
    BoneWeights* fBoneWeights;
    uint16_t*    fIndices;

    SkRect  fBounds;    // computed to be the union of the fPositions[]
    int     fVertexCnt;
    int     fIndexCnt;

    bool fIsVolatile;

    VertexMode fMode;
    // below here is where the actual array data is stored.
};

#endif