Mike Reed | 97eb4fe | 2017-03-14 12:04:16 -0400 | [diff] [blame] | 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 | |
Hal Canary | fdcfb8b | 2018-06-13 09:42:32 -0400 | [diff] [blame] | 8 | #include "SkVertices.h" |
Hal Canary | c640d0d | 2018-06-13 09:59:02 -0400 | [diff] [blame] | 9 | |
| 10 | #include "SkAtomics.h" |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 11 | #include "SkData.h" |
| 12 | #include "SkReader32.h" |
Mike Reed | f00faa3 | 2018-01-09 13:30:54 -0500 | [diff] [blame] | 13 | #include "SkSafeMath.h" |
Mike Reed | 165fa63 | 2018-01-23 11:50:25 -0500 | [diff] [blame] | 14 | #include "SkSafeRange.h" |
Hal Canary | c640d0d | 2018-06-13 09:59:02 -0400 | [diff] [blame] | 15 | #include "SkTo.h" |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 16 | #include "SkWriter32.h" |
Mike Klein | 79aea6a | 2018-06-11 10:45:26 -0400 | [diff] [blame] | 17 | #include <new> |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 18 | |
Mike Reed | 9a8065d | 2017-03-14 21:05:17 -0400 | [diff] [blame] | 19 | static int32_t gNextID = 1; |
| 20 | static int32_t next_id() { |
| 21 | int32_t id; |
| 22 | do { |
| 23 | id = sk_atomic_inc(&gNextID); |
| 24 | } while (id == SK_InvalidGenID); |
| 25 | return id; |
| 26 | } |
| 27 | |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 28 | struct SkVertices::Sizes { |
Brian Salomon | cccafe8 | 2018-04-28 16:13:08 -0400 | [diff] [blame] | 29 | Sizes(SkVertices::VertexMode mode, int vertexCount, int indexCount, bool hasTexs, |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 30 | bool hasColors, bool hasBones) { |
Mike Reed | f00faa3 | 2018-01-09 13:30:54 -0500 | [diff] [blame] | 31 | SkSafeMath safe; |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 32 | |
Mike Reed | f00faa3 | 2018-01-09 13:30:54 -0500 | [diff] [blame] | 33 | fVSize = safe.mul(vertexCount, sizeof(SkPoint)); |
| 34 | fTSize = hasTexs ? safe.mul(vertexCount, sizeof(SkPoint)) : 0; |
| 35 | fCSize = hasColors ? safe.mul(vertexCount, sizeof(SkColor)) : 0; |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 36 | fBISize = hasBones ? safe.mul(vertexCount, sizeof(BoneIndices)) : 0; |
| 37 | fBWSize = hasBones ? safe.mul(vertexCount, sizeof(BoneWeights)) : 0; |
Brian Salomon | cccafe8 | 2018-04-28 16:13:08 -0400 | [diff] [blame] | 38 | |
| 39 | fBuilderTriFanISize = 0; |
Mike Reed | f00faa3 | 2018-01-09 13:30:54 -0500 | [diff] [blame] | 40 | fISize = safe.mul(indexCount, sizeof(uint16_t)); |
Brian Salomon | cccafe8 | 2018-04-28 16:13:08 -0400 | [diff] [blame] | 41 | if (kTriangleFan_VertexMode == mode) { |
| 42 | int numFanTris = 0; |
| 43 | if (indexCount) { |
| 44 | fBuilderTriFanISize = fISize; |
| 45 | numFanTris = indexCount - 2; |
| 46 | } else { |
| 47 | numFanTris = vertexCount - 2; |
| 48 | // By forcing this to become indexed we are adding a constraint to the maximum |
| 49 | // number of vertices. |
Ben Wagner | dde9b52 | 2018-06-15 16:19:56 -0400 | [diff] [blame] | 50 | if (vertexCount > (SkTo<int>(UINT16_MAX) + 1)) { |
Brian Salomon | cccafe8 | 2018-04-28 16:13:08 -0400 | [diff] [blame] | 51 | sk_bzero(this, sizeof(*this)); |
| 52 | return; |
| 53 | } |
| 54 | } |
| 55 | if (numFanTris <= 0) { |
| 56 | sk_bzero(this, sizeof(*this)); |
| 57 | return; |
| 58 | } |
| 59 | fISize = safe.mul(numFanTris, 3 * sizeof(uint16_t)); |
| 60 | } |
| 61 | |
Mike Reed | f00faa3 | 2018-01-09 13:30:54 -0500 | [diff] [blame] | 62 | fTotal = safe.add(sizeof(SkVertices), |
| 63 | safe.add(fVSize, |
| 64 | safe.add(fTSize, |
| 65 | safe.add(fCSize, |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 66 | safe.add(fBISize, |
| 67 | safe.add(fBWSize, |
| 68 | fISize)))))); |
Mike Reed | f00faa3 | 2018-01-09 13:30:54 -0500 | [diff] [blame] | 69 | |
| 70 | if (safe.ok()) { |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 71 | fArrays = fTotal - sizeof(SkVertices); // just the sum of the arrays |
Mike Reed | f00faa3 | 2018-01-09 13:30:54 -0500 | [diff] [blame] | 72 | } else { |
| 73 | sk_bzero(this, sizeof(*this)); |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 74 | } |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 75 | } |
| 76 | |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 77 | bool isValid() const { return fTotal != 0; } |
| 78 | |
| 79 | size_t fTotal; // size of entire SkVertices allocation (obj + arrays) |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 80 | size_t fArrays; // size of all the arrays (V + T + C + BI + BW + I) |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 81 | size_t fVSize; |
| 82 | size_t fTSize; |
| 83 | size_t fCSize; |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 84 | size_t fBISize; |
| 85 | size_t fBWSize; |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 86 | size_t fISize; |
Brian Salomon | cccafe8 | 2018-04-28 16:13:08 -0400 | [diff] [blame] | 87 | |
| 88 | // For indexed tri-fans this is the number of amount of space fo indices needed in the builder |
| 89 | // before conversion to indexed triangles (or zero if not indexed or not a triangle fan). |
| 90 | size_t fBuilderTriFanISize; |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 91 | }; |
| 92 | |
Mike Reed | 887cdf1 | 2017-04-03 11:11:09 -0400 | [diff] [blame] | 93 | SkVertices::Builder::Builder(VertexMode mode, int vertexCount, int indexCount, |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 94 | uint32_t builderFlags) { |
| 95 | bool hasTexs = SkToBool(builderFlags & SkVertices::kHasTexCoords_BuilderFlag); |
| 96 | bool hasColors = SkToBool(builderFlags & SkVertices::kHasColors_BuilderFlag); |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 97 | bool hasBones = SkToBool(builderFlags & SkVertices::kHasBones_BuilderFlag); |
Ruiqi Mao | 9a6e42f | 2018-07-09 14:16:56 -0400 | [diff] [blame] | 98 | bool isVolatile = !SkToBool(builderFlags & SkVertices::kIsNonVolatile_BuilderFlag); |
| 99 | this->init(mode, vertexCount, indexCount, isVolatile, |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 100 | SkVertices::Sizes(mode, vertexCount, indexCount, hasTexs, hasColors, hasBones)); |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 101 | } |
Mike Reed | 97eb4fe | 2017-03-14 12:04:16 -0400 | [diff] [blame] | 102 | |
Ruiqi Mao | 9a6e42f | 2018-07-09 14:16:56 -0400 | [diff] [blame] | 103 | SkVertices::Builder::Builder(VertexMode mode, int vertexCount, int indexCount, bool isVolatile, |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 104 | const SkVertices::Sizes& sizes) { |
Ruiqi Mao | 9a6e42f | 2018-07-09 14:16:56 -0400 | [diff] [blame] | 105 | this->init(mode, vertexCount, indexCount, isVolatile, sizes); |
Mike Reed | 0c492cf | 2017-03-16 16:44:25 +0000 | [diff] [blame] | 106 | } |
| 107 | |
Ruiqi Mao | 9a6e42f | 2018-07-09 14:16:56 -0400 | [diff] [blame] | 108 | void SkVertices::Builder::init(VertexMode mode, int vertexCount, int indexCount, bool isVolatile, |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 109 | const SkVertices::Sizes& sizes) { |
| 110 | if (!sizes.isValid()) { |
| 111 | return; // fVertices will already be null |
| 112 | } |
| 113 | |
| 114 | void* storage = ::operator new (sizes.fTotal); |
Brian Salomon | cccafe8 | 2018-04-28 16:13:08 -0400 | [diff] [blame] | 115 | if (sizes.fBuilderTriFanISize) { |
| 116 | fIntermediateFanIndices.reset(new uint8_t[sizes.fBuilderTriFanISize]); |
| 117 | } |
| 118 | |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 119 | fVertices.reset(new (storage) SkVertices); |
| 120 | |
| 121 | // need to point past the object to store the arrays |
| 122 | char* ptr = (char*)storage + sizeof(SkVertices); |
| 123 | |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 124 | fVertices->fPositions = (SkPoint*)ptr; ptr += sizes.fVSize; |
| 125 | fVertices->fTexs = sizes.fTSize ? (SkPoint*)ptr : nullptr; ptr += sizes.fTSize; |
| 126 | fVertices->fColors = sizes.fCSize ? (SkColor*)ptr : nullptr; ptr += sizes.fCSize; |
| 127 | fVertices->fBoneIndices = sizes.fBISize ? (BoneIndices*) ptr : nullptr; ptr += sizes.fBISize; |
| 128 | fVertices->fBoneWeights = sizes.fBWSize ? (BoneWeights*) ptr : nullptr; ptr += sizes.fBWSize; |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 129 | fVertices->fIndices = sizes.fISize ? (uint16_t*)ptr : nullptr; |
| 130 | fVertices->fVertexCnt = vertexCount; |
| 131 | fVertices->fIndexCnt = indexCount; |
Ruiqi Mao | 9a6e42f | 2018-07-09 14:16:56 -0400 | [diff] [blame] | 132 | fVertices->fIsVolatile = isVolatile; |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 133 | fVertices->fMode = mode; |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 134 | |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 135 | // We defer assigning fBounds and fUniqueID until detach() is called |
Mike Reed | 97eb4fe | 2017-03-14 12:04:16 -0400 | [diff] [blame] | 136 | } |
| 137 | |
| 138 | sk_sp<SkVertices> SkVertices::Builder::detach() { |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 139 | if (fVertices) { |
| 140 | fVertices->fBounds.set(fVertices->fPositions, fVertices->fVertexCnt); |
Brian Salomon | cccafe8 | 2018-04-28 16:13:08 -0400 | [diff] [blame] | 141 | if (fVertices->fMode == kTriangleFan_VertexMode) { |
| 142 | if (fIntermediateFanIndices.get()) { |
| 143 | SkASSERT(fVertices->fIndexCnt); |
| 144 | auto tempIndices = this->indices(); |
| 145 | for (int t = 0; t < fVertices->fIndexCnt - 2; ++t) { |
| 146 | fVertices->fIndices[3 * t + 0] = tempIndices[0]; |
| 147 | fVertices->fIndices[3 * t + 1] = tempIndices[t + 1]; |
| 148 | fVertices->fIndices[3 * t + 2] = tempIndices[t + 2]; |
| 149 | } |
| 150 | fVertices->fIndexCnt = 3 * (fVertices->fIndexCnt - 2); |
| 151 | } else { |
| 152 | SkASSERT(!fVertices->fIndexCnt); |
| 153 | for (int t = 0; t < fVertices->fVertexCnt - 2; ++t) { |
| 154 | fVertices->fIndices[3 * t + 0] = 0; |
| 155 | fVertices->fIndices[3 * t + 1] = SkToU16(t + 1); |
| 156 | fVertices->fIndices[3 * t + 2] = SkToU16(t + 2); |
| 157 | } |
| 158 | fVertices->fIndexCnt = 3 * (fVertices->fVertexCnt - 2); |
| 159 | } |
| 160 | fVertices->fMode = kTriangles_VertexMode; |
| 161 | } |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 162 | fVertices->fUniqueID = next_id(); |
| 163 | return std::move(fVertices); // this will null fVertices after the return |
Mike Reed | 97eb4fe | 2017-03-14 12:04:16 -0400 | [diff] [blame] | 164 | } |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 165 | return nullptr; |
Mike Reed | 7d9f9e3 | 2017-03-15 18:35:07 +0000 | [diff] [blame] | 166 | } |
| 167 | |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 168 | int SkVertices::Builder::vertexCount() const { |
| 169 | return fVertices ? fVertices->vertexCount() : 0; |
| 170 | } |
| 171 | |
| 172 | int SkVertices::Builder::indexCount() const { |
| 173 | return fVertices ? fVertices->indexCount() : 0; |
| 174 | } |
| 175 | |
Ruiqi Mao | 9a6e42f | 2018-07-09 14:16:56 -0400 | [diff] [blame] | 176 | bool SkVertices::Builder::isVolatile() const { |
| 177 | return fVertices ? fVertices->isVolatile() : true; |
| 178 | } |
| 179 | |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 180 | SkPoint* SkVertices::Builder::positions() { |
| 181 | return fVertices ? const_cast<SkPoint*>(fVertices->positions()) : nullptr; |
| 182 | } |
| 183 | |
| 184 | SkPoint* SkVertices::Builder::texCoords() { |
| 185 | return fVertices ? const_cast<SkPoint*>(fVertices->texCoords()) : nullptr; |
| 186 | } |
| 187 | |
| 188 | SkColor* SkVertices::Builder::colors() { |
| 189 | return fVertices ? const_cast<SkColor*>(fVertices->colors()) : nullptr; |
| 190 | } |
| 191 | |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 192 | SkVertices::BoneIndices* SkVertices::Builder::boneIndices() { |
| 193 | return fVertices ? const_cast<BoneIndices*>(fVertices->boneIndices()) : nullptr; |
| 194 | } |
| 195 | |
| 196 | SkVertices::BoneWeights* SkVertices::Builder::boneWeights() { |
| 197 | return fVertices ? const_cast<BoneWeights*>(fVertices->boneWeights()) : nullptr; |
| 198 | } |
| 199 | |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 200 | uint16_t* SkVertices::Builder::indices() { |
Brian Salomon | cccafe8 | 2018-04-28 16:13:08 -0400 | [diff] [blame] | 201 | if (!fVertices) { |
| 202 | return nullptr; |
| 203 | } |
| 204 | if (fIntermediateFanIndices) { |
| 205 | return reinterpret_cast<uint16_t*>(fIntermediateFanIndices.get()); |
| 206 | } |
| 207 | return const_cast<uint16_t*>(fVertices->indices()); |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 208 | } |
| 209 | |
Ruiqi Mao | c97a339 | 2018-08-15 10:44:19 -0400 | [diff] [blame] | 210 | /** Makes a copy of the SkVertices and applies a set of bones, then returns the deformed |
| 211 | vertices. |
| 212 | |
| 213 | @param bones The bones to apply. |
| 214 | @param boneCount The number of bones. |
| 215 | @return The transformed SkVertices. |
| 216 | */ |
| 217 | sk_sp<SkVertices> SkVertices::applyBones(const SkVertices::Bone bones[], int boneCount) const { |
| 218 | // If there aren't any bones, then nothing changes. |
| 219 | // We don't check if the SkVertices object has bone indices/weights because there is the case |
| 220 | // where the object can have no indices/weights but still have a world transform applied. |
| 221 | if (!bones || !boneCount) { |
| 222 | return sk_ref_sp(this); |
| 223 | } |
| 224 | SkASSERT(boneCount >= 1); |
| 225 | |
| 226 | // Copy the SkVertices. |
| 227 | sk_sp<SkVertices> copy = SkVertices::MakeCopy(this->mode(), |
| 228 | this->vertexCount(), |
| 229 | this->positions(), |
| 230 | this->texCoords(), |
| 231 | this->colors(), |
| 232 | nullptr, |
| 233 | nullptr, |
| 234 | this->indexCount(), |
| 235 | this->indices()); |
| 236 | |
| 237 | // Transform the positions. |
| 238 | for (int i = 0; i < this->vertexCount(); i++) { |
| 239 | SkPoint& position = copy->fPositions[i]; |
| 240 | |
| 241 | // Apply the world transform. |
| 242 | position = bones[0].mapPoint(position); |
| 243 | |
| 244 | // Apply the bone deformations. |
| 245 | if (boneCount > 1) { |
| 246 | SkASSERT(this->boneIndices()); |
| 247 | SkASSERT(this->boneWeights()); |
| 248 | |
| 249 | SkPoint result = SkPoint::Make(0.0f, 0.0f); |
| 250 | const SkVertices::BoneIndices& indices = this->boneIndices()[i]; |
| 251 | const SkVertices::BoneWeights& weights = this->boneWeights()[i]; |
| 252 | for (int j = 0; j < 4; j++) { |
| 253 | int index = indices[j]; |
| 254 | float weight = weights[j]; |
| 255 | if (index == 0 || weight == 0.0f) { |
| 256 | continue; |
| 257 | } |
| 258 | SkASSERT(index < boneCount); |
| 259 | |
| 260 | // result += M * v * w. |
| 261 | result += bones[index].mapPoint(position) * weight; |
| 262 | } |
| 263 | position = result; |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | // Recalculate the bounds. |
| 268 | copy->fBounds.set(copy->fPositions, copy->fVertexCnt); |
| 269 | |
| 270 | return copy; |
| 271 | } |
| 272 | |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 273 | /////////////////////////////////////////////////////////////////////////////////////////////////// |
| 274 | |
Mike Reed | 887cdf1 | 2017-04-03 11:11:09 -0400 | [diff] [blame] | 275 | sk_sp<SkVertices> SkVertices::MakeCopy(VertexMode mode, int vertexCount, |
Mike Reed | 97eb4fe | 2017-03-14 12:04:16 -0400 | [diff] [blame] | 276 | const SkPoint pos[], const SkPoint texs[], |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 277 | const SkColor colors[], |
| 278 | const BoneIndices boneIndices[], |
| 279 | const BoneWeights boneWeights[], |
Ruiqi Mao | 9a6e42f | 2018-07-09 14:16:56 -0400 | [diff] [blame] | 280 | int indexCount, const uint16_t indices[], |
| 281 | bool isVolatile) { |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 282 | SkASSERT((!boneIndices && !boneWeights) || (boneIndices && boneWeights)); |
| 283 | Sizes sizes(mode, |
| 284 | vertexCount, |
| 285 | indexCount, |
| 286 | texs != nullptr, |
| 287 | colors != nullptr, |
| 288 | boneIndices != nullptr); |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 289 | if (!sizes.isValid()) { |
Mike Reed | 97eb4fe | 2017-03-14 12:04:16 -0400 | [diff] [blame] | 290 | return nullptr; |
| 291 | } |
| 292 | |
Ruiqi Mao | 9a6e42f | 2018-07-09 14:16:56 -0400 | [diff] [blame] | 293 | Builder builder(mode, vertexCount, indexCount, isVolatile, sizes); |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 294 | SkASSERT(builder.isValid()); |
| 295 | |
| 296 | sk_careful_memcpy(builder.positions(), pos, sizes.fVSize); |
| 297 | sk_careful_memcpy(builder.texCoords(), texs, sizes.fTSize); |
| 298 | sk_careful_memcpy(builder.colors(), colors, sizes.fCSize); |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 299 | sk_careful_memcpy(builder.boneIndices(), boneIndices, sizes.fBISize); |
| 300 | sk_careful_memcpy(builder.boneWeights(), boneWeights, sizes.fBWSize); |
Brian Salomon | cccafe8 | 2018-04-28 16:13:08 -0400 | [diff] [blame] | 301 | size_t isize = (mode == kTriangleFan_VertexMode) ? sizes.fBuilderTriFanISize : sizes.fISize; |
| 302 | sk_careful_memcpy(builder.indices(), indices, isize); |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 303 | |
Mike Reed | 97eb4fe | 2017-03-14 12:04:16 -0400 | [diff] [blame] | 304 | return builder.detach(); |
| 305 | } |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 306 | |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 307 | size_t SkVertices::approximateSize() const { |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 308 | Sizes sizes(fMode, |
| 309 | fVertexCnt, |
| 310 | fIndexCnt, |
| 311 | this->hasTexCoords(), |
| 312 | this->hasColors(), |
| 313 | this->hasBones()); |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 314 | SkASSERT(sizes.isValid()); |
| 315 | return sizeof(SkVertices) + sizes.fArrays; |
| 316 | } |
| 317 | |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 318 | /////////////////////////////////////////////////////////////////////////////////////////////////// |
| 319 | |
Ruiqi Mao | c05aa7d | 2018-07-03 21:18:07 +0000 | [diff] [blame] | 320 | // storage = packed | vertex_count | index_count | pos[] | texs[] | colors[] | boneIndices[] | |
| 321 | // boneWeights[] | indices[] |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 322 | // = header + arrays |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 323 | |
| 324 | #define kMode_Mask 0x0FF |
| 325 | #define kHasTexs_Mask 0x100 |
| 326 | #define kHasColors_Mask 0x200 |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 327 | #define kHasBones_Mask 0x400 |
Ruiqi Mao | 9a6e42f | 2018-07-09 14:16:56 -0400 | [diff] [blame] | 328 | #define kIsNonVolatile_Mask 0x800 |
Ruiqi Mao | c05aa7d | 2018-07-03 21:18:07 +0000 | [diff] [blame] | 329 | #define kHeaderSize (3 * sizeof(uint32_t)) |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 330 | |
| 331 | sk_sp<SkData> SkVertices::encode() const { |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 332 | // packed has room for addtional flags in the future (e.g. versioning) |
| 333 | uint32_t packed = static_cast<uint32_t>(fMode); |
| 334 | SkASSERT((packed & ~kMode_Mask) == 0); // our mode fits in the mask bits |
| 335 | if (this->hasTexCoords()) { |
| 336 | packed |= kHasTexs_Mask; |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 337 | } |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 338 | if (this->hasColors()) { |
| 339 | packed |= kHasColors_Mask; |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 340 | } |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 341 | if (this->hasBones()) { |
| 342 | packed |= kHasBones_Mask; |
| 343 | } |
Ruiqi Mao | 9a6e42f | 2018-07-09 14:16:56 -0400 | [diff] [blame] | 344 | if (!this->isVolatile()) { |
| 345 | packed |= kIsNonVolatile_Mask; |
| 346 | } |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 347 | |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 348 | Sizes sizes(fMode, |
| 349 | fVertexCnt, |
| 350 | fIndexCnt, |
| 351 | this->hasTexCoords(), |
| 352 | this->hasColors(), |
| 353 | this->hasBones()); |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 354 | SkASSERT(sizes.isValid()); |
Brian Salomon | cccafe8 | 2018-04-28 16:13:08 -0400 | [diff] [blame] | 355 | SkASSERT(!sizes.fBuilderTriFanISize); |
Mike Reed | 6ff6af9 | 2017-04-05 17:05:16 -0400 | [diff] [blame] | 356 | // need to force alignment to 4 for SkWriter32 -- will pad w/ 0s as needed |
| 357 | const size_t size = SkAlign4(kHeaderSize + sizes.fArrays); |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 358 | |
| 359 | sk_sp<SkData> data = SkData::MakeUninitialized(size); |
| 360 | SkWriter32 writer(data->writable_data(), data->size()); |
| 361 | |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 362 | writer.write32(packed); |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 363 | writer.write32(fVertexCnt); |
| 364 | writer.write32(fIndexCnt); |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 365 | writer.write(fPositions, sizes.fVSize); |
| 366 | writer.write(fTexs, sizes.fTSize); |
| 367 | writer.write(fColors, sizes.fCSize); |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 368 | writer.write(fBoneIndices, sizes.fBISize); |
| 369 | writer.write(fBoneWeights, sizes.fBWSize); |
Mike Reed | 6ff6af9 | 2017-04-05 17:05:16 -0400 | [diff] [blame] | 370 | // if index-count is odd, we won't be 4-bytes aligned, so we call the pad version |
| 371 | writer.writePad(fIndices, sizes.fISize); |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 372 | |
| 373 | return data; |
| 374 | } |
| 375 | |
| 376 | sk_sp<SkVertices> SkVertices::Decode(const void* data, size_t length) { |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 377 | if (length < kHeaderSize) { |
| 378 | return nullptr; |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 379 | } |
| 380 | |
| 381 | SkReader32 reader(data, length); |
Mike Reed | 165fa63 | 2018-01-23 11:50:25 -0500 | [diff] [blame] | 382 | SkSafeRange safe; |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 383 | |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 384 | const uint32_t packed = reader.readInt(); |
Mike Reed | d2bc620 | 2018-02-01 10:48:59 -0500 | [diff] [blame] | 385 | const int vertexCount = safe.checkGE(reader.readInt(), 0); |
| 386 | const int indexCount = safe.checkGE(reader.readInt(), 0); |
Mike Reed | 165fa63 | 2018-01-23 11:50:25 -0500 | [diff] [blame] | 387 | const VertexMode mode = safe.checkLE<VertexMode>(packed & kMode_Mask, |
| 388 | SkVertices::kLast_VertexMode); |
Mike Reed | d2bc620 | 2018-02-01 10:48:59 -0500 | [diff] [blame] | 389 | if (!safe) { |
| 390 | return nullptr; |
| 391 | } |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 392 | const bool hasTexs = SkToBool(packed & kHasTexs_Mask); |
| 393 | const bool hasColors = SkToBool(packed & kHasColors_Mask); |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 394 | const bool hasBones = SkToBool(packed & kHasBones_Mask); |
Ruiqi Mao | 9a6e42f | 2018-07-09 14:16:56 -0400 | [diff] [blame] | 395 | const bool isVolatile = !SkToBool(packed & kIsNonVolatile_Mask); |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 396 | Sizes sizes(mode, vertexCount, indexCount, hasTexs, hasColors, hasBones); |
Mike Reed | d2bc620 | 2018-02-01 10:48:59 -0500 | [diff] [blame] | 397 | if (!sizes.isValid()) { |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 398 | return nullptr; |
| 399 | } |
Mike Reed | 6ff6af9 | 2017-04-05 17:05:16 -0400 | [diff] [blame] | 400 | // logically we can be only 2-byte aligned, but our buffer is always 4-byte aligned |
| 401 | if (SkAlign4(kHeaderSize + sizes.fArrays) != length) { |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 402 | return nullptr; |
| 403 | } |
| 404 | |
Ruiqi Mao | 9a6e42f | 2018-07-09 14:16:56 -0400 | [diff] [blame] | 405 | Builder builder(mode, vertexCount, indexCount, isVolatile, sizes); |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 406 | |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 407 | reader.read(builder.positions(), sizes.fVSize); |
| 408 | reader.read(builder.texCoords(), sizes.fTSize); |
| 409 | reader.read(builder.colors(), sizes.fCSize); |
Ruiqi Mao | f510149 | 2018-06-29 14:32:21 -0400 | [diff] [blame] | 410 | reader.read(builder.boneIndices(), sizes.fBISize); |
| 411 | reader.read(builder.boneWeights(), sizes.fBWSize); |
Brian Salomon | cccafe8 | 2018-04-28 16:13:08 -0400 | [diff] [blame] | 412 | size_t isize = (mode == kTriangleFan_VertexMode) ? sizes.fBuilderTriFanISize : sizes.fISize; |
| 413 | reader.read(builder.indices(), isize); |
Mike Reed | d2bc620 | 2018-02-01 10:48:59 -0500 | [diff] [blame] | 414 | if (indexCount > 0) { |
| 415 | // validate that the indicies are in range |
| 416 | SkASSERT(indexCount == builder.indexCount()); |
| 417 | const uint16_t* indices = builder.indices(); |
| 418 | for (int i = 0; i < indexCount; ++i) { |
| 419 | if (indices[i] >= (unsigned)vertexCount) { |
| 420 | return nullptr; |
| 421 | } |
| 422 | } |
| 423 | } |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 424 | return builder.detach(); |
| 425 | } |
Yong-Hwan Baek | 701a3ca | 2018-04-20 21:44:43 +0900 | [diff] [blame] | 426 | |
| 427 | void SkVertices::operator delete(void* p) |
| 428 | { |
| 429 | ::operator delete(p); |
| 430 | } |