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 mapPointBone79 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 mapRectBone85 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 isValid()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 uniqueID()210 uint32_t uniqueID() const { return fUniqueID; } mode()211 VertexMode mode() const { return fMode; } bounds()212 const SkRect& bounds() const { return fBounds; } 213 hasColors()214 bool hasColors() const { return SkToBool(this->colors()); } hasTexCoords()215 bool hasTexCoords() const { return SkToBool(this->texCoords()); } hasBones()216 bool hasBones() const { return SkToBool(this->boneIndices()); } hasIndices()217 bool hasIndices() const { return SkToBool(this->indices()); } 218 vertexCount()219 int vertexCount() const { return fVertexCnt; } positions()220 const SkPoint* positions() const { return fPositions; } texCoords()221 const SkPoint* texCoords() const { return fTexs; } colors()222 const SkColor* colors() const { return fColors; } 223 boneIndices()224 const BoneIndices* boneIndices() const { return fBoneIndices; } boneWeights()225 const BoneWeights* boneWeights() const { return fBoneWeights; } 226 indexCount()227 int indexCount() const { return fIndexCnt; } indices()228 const uint16_t* indices() const { return fIndices; } 229 isVolatile()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: SkVertices()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