aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--BUILD.gn19
-rw-r--r--include/core/SkCanvas.h42
-rw-r--r--include/core/SkCanvasVirtualEnforcer.h4
-rw-r--r--include/core/SkOverdrawCanvas.h3
-rw-r--r--include/core/SkVertices.h82
-rw-r--r--include/utils/SkLuaCanvas.h3
-rw-r--r--include/utils/SkNWayCanvas.h3
-rw-r--r--include/utils/SkNoDrawCanvas.h3
-rw-r--r--include/utils/SkPaintFilterCanvas.h3
-rw-r--r--resources/nima/Robot.nimabin33062 -> 33446 bytes
-rw-r--r--src/core/SkBitmapDevice.cpp9
-rw-r--r--src/core/SkBitmapDevice.h3
-rw-r--r--src/core/SkCanvas.cpp24
-rw-r--r--src/core/SkColorSpaceXformCanvas.cpp7
-rw-r--r--src/core/SkDevice.cpp4
-rw-r--r--src/core/SkDevice.h6
-rw-r--r--src/core/SkDraw.h7
-rw-r--r--src/core/SkDraw_vertices.cpp88
-rw-r--r--src/core/SkLiteDL.cpp20
-rw-r--r--src/core/SkLiteDL.h3
-rw-r--r--src/core/SkLiteRecorder.cpp6
-rw-r--r--src/core/SkLiteRecorder.h3
-rw-r--r--src/core/SkOverdrawCanvas.cpp9
-rw-r--r--src/core/SkPicturePlayback.cpp6
-rw-r--r--src/core/SkPictureRecord.cpp10
-rw-r--r--src/core/SkPictureRecord.h3
-rw-r--r--src/core/SkRecordDraw.cpp2
-rw-r--r--src/core/SkRecorder.cpp10
-rw-r--r--src/core/SkRecorder.h3
-rw-r--r--src/core/SkRecords.h2
-rw-r--r--src/core/SkThreadedBMPDevice.cpp9
-rw-r--r--src/core/SkThreadedBMPDevice.h3
-rw-r--r--src/core/SkVertices.cpp76
-rw-r--r--src/gpu/SkGpuDevice.cpp4
-rw-r--r--src/gpu/SkGpuDevice.h3
-rw-r--r--src/pdf/SkPDFDevice.cpp3
-rw-r--r--src/pdf/SkPDFDevice.h3
-rw-r--r--src/pipe/SkPipeCanvas.cpp6
-rw-r--r--src/pipe/SkPipeCanvas.h3
-rw-r--r--src/pipe/SkPipeReader.cpp9
-rw-r--r--src/svg/SkSVGDevice.cpp3
-rw-r--r--src/svg/SkSVGDevice.h3
-rw-r--r--src/utils/SkLuaCanvas.cpp3
-rw-r--r--src/utils/SkNWayCanvas.cpp6
-rw-r--r--src/utils/SkPaintFilterCanvas.cpp5
-rw-r--r--src/utils/SkShadowUtils.cpp6
-rw-r--r--src/xps/SkXPSDevice.cpp6
-rw-r--r--src/xps/SkXPSDevice.h3
-rw-r--r--tools/debugger/SkDebugCanvas.cpp5
-rw-r--r--tools/debugger/SkDebugCanvas.h3
-rw-r--r--tools/flags/SkCommonFlags.cpp2
-rw-r--r--tools/flags/SkCommonFlags.h1
-rw-r--r--tools/viewer/NIMASlide.cpp516
-rw-r--r--tools/viewer/NIMASlide.h59
-rw-r--r--tools/viewer/Viewer.cpp10
55 files changed, 1013 insertions, 124 deletions
diff --git a/BUILD.gn b/BUILD.gn
index 97cbf731f6..f10d232fcc 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1551,9 +1551,13 @@ if (skia_enable_tools) {
":xml",
"modules/sksg:samples",
"modules/skshaper",
- "//third_party/Nima-Cpp",
]
+ # NIMA does not build on Windows clang
+ if (!is_win || !is_clang) {
+ deps += [ "//third_party/Nima-Cpp" ]
+ }
+
if (skia_use_lua) {
sources += [ "samplecode/SampleLua.cpp" ]
deps += [
@@ -1581,10 +1585,14 @@ if (skia_enable_tools) {
":tool_utils",
"modules/skottie",
"modules/sksg",
- "//third_party/Nima-Cpp",
"//third_party/jsoncpp",
"//third_party/libpng",
]
+
+ # NIMA does not build on Windows clang
+ if (!is_win || !is_clang) {
+ deps += [ "//third_party/Nima-Cpp" ]
+ }
}
}
@@ -2005,9 +2013,14 @@ if (skia_enable_tools) {
":views",
"modules/skottie",
"modules/sksg",
- "//third_party/Nima-Cpp",
"//third_party/imgui",
]
+
+ # NIMA does not build on Windows clang
+ if (!is_win || !is_clang) {
+ sources += [ "tools/viewer/NIMASlide.cpp" ]
+ deps += [ "//third_party/Nima-Cpp" ]
+ }
}
if (is_android) {
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 5a307c8e6b..15ed034db6 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -2149,6 +2149,40 @@ public:
*/
void drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode, const SkPaint& paint);
+ /** Draw SkVertices vertices, a triangle mesh, using clip and SkMatrix. Bone data is used to
+ deform vertices with bone weights.
+ If vertices texs and vertices colors are defined in vertices, and SkPaint paint
+ contains SkShader, SkBlendMode mode combines vertices colors with SkShader.
+ The first element of bones should be an object to world space transformation matrix that
+ will be applied before performing mesh deformations. If no such transformation is needed,
+ it should be the identity matrix.
+
+ @param vertices triangle mesh to draw
+ @param bones bone matrix data
+ @param boneCount number of bone matrices
+ @param mode combines vertices colors with SkShader, if both are present
+ @param paint specifies the SkShader, used as SkVertices texture, may be nullptr
+ */
+ void drawVertices(const SkVertices* vertices, const SkMatrix* bones, int boneCount,
+ SkBlendMode mode, const SkPaint& paint);
+
+ /** Draw SkVertices vertices, a triangle mesh, using clip and SkMatrix. Bone data is used to
+ deform vertices with bone weights.
+ If vertices texs and vertices colors are defined in vertices, and SkPaint paint
+ contains SkShader, SkBlendMode mode combines vertices colors with SkShader.
+ The first element of bones should be an object to world space transformation matrix that
+ will be applied before performing mesh deformations. If no such transformation is needed,
+ it should be the identity matrix.
+
+ @param vertices triangle mesh to draw
+ @param bones bone matrix data
+ @param boneCount number of bone matrices
+ @param mode combines vertices colors with SkShader, if both are present
+ @param paint specifies the SkShader, used as SkVertices texture, may be nullptr
+ */
+ void drawVertices(const sk_sp<SkVertices> vertices, const SkMatrix* bones, int boneCount,
+ SkBlendMode mode, const SkPaint& paint);
+
/** Draws a Coons patch: the interpolation of four cubics with shared corners,
associating a color, and optionally a texture SkPoint, with each corner.
@@ -2472,8 +2506,14 @@ protected:
const SkPoint texCoords[4], SkBlendMode mode, const SkPaint& paint);
virtual void onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
const SkPaint& paint);
+
+ // TODO: Remove old signature
virtual void onDrawVerticesObject(const SkVertices* vertices, SkBlendMode mode,
- const SkPaint& paint);
+ const SkPaint& paint) {
+ this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
+ }
+ virtual void onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
+ int boneCount, SkBlendMode mode, const SkPaint& paint);
virtual void onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint);
virtual void onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
diff --git a/include/core/SkCanvasVirtualEnforcer.h b/include/core/SkCanvasVirtualEnforcer.h
index 1999802170..84b209d895 100644
--- a/include/core/SkCanvasVirtualEnforcer.h
+++ b/include/core/SkCanvasVirtualEnforcer.h
@@ -48,8 +48,8 @@ protected:
const SkPaint& paint) override = 0;
void onDrawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint pts[],
const SkPaint& paint) override = 0;
- void onDrawVerticesObject(const SkVertices* vertices, SkBlendMode mode,
- const SkPaint& paint) override = 0;
+ void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+ const SkPaint&) override = 0;
void onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy,
const SkPaint* paint) override = 0;
diff --git a/include/core/SkOverdrawCanvas.h b/include/core/SkOverdrawCanvas.h
index 47b5e04872..380f9ebb87 100644
--- a/include/core/SkOverdrawCanvas.h
+++ b/include/core/SkOverdrawCanvas.h
@@ -39,7 +39,8 @@ public:
void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
void onDrawRRect(const SkRRect&, const SkPaint&) override;
void onDrawPoints(PointMode, size_t, const SkPoint[], const SkPaint&) override;
- void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
+ void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+ const SkPaint&) override;
void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
int, SkBlendMode, const SkRect*, const SkPaint*) override;
void onDrawPath(const SkPath&, const SkPaint&) override;
diff --git a/include/core/SkVertices.h b/include/core/SkVertices.h
index d5e97e12d5..6c4fb390d0 100644
--- a/include/core/SkVertices.h
+++ b/include/core/SkVertices.h
@@ -19,6 +19,20 @@
*/
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,
@@ -28,21 +42,60 @@ public:
};
/**
- * Create a vertices by copying the specified arrays. texs and colors may be nullptr,
- * and indices is ignored if indexCount == 0.
+ * 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[]);
static sk_sp<SkVertices> MakeCopy(VertexMode mode, int vertexCount,
const SkPoint positions[],
const SkPoint texs[],
+ const SkColor colors[],
+ const BoneIndices boneIndices[],
+ const BoneWeights boneWeights[]) {
+ return MakeCopy(mode,
+ vertexCount,
+ positions,
+ texs,
+ colors,
+ boneIndices,
+ boneWeights,
+ 0,
+ nullptr);
+ }
+
+ static sk_sp<SkVertices> MakeCopy(VertexMode mode, int vertexCount,
+ const SkPoint positions[],
+ const SkPoint texs[],
+ const SkColor colors[],
+ int indexCount,
+ const uint16_t indices[]) {
+ return MakeCopy(mode,
+ vertexCount,
+ positions,
+ texs,
+ colors,
+ nullptr,
+ nullptr,
+ indexCount,
+ indices);
+ }
+
+ static sk_sp<SkVertices> MakeCopy(VertexMode mode, int vertexCount,
+ const SkPoint positions[],
+ const SkPoint texs[],
const SkColor colors[]) {
- return MakeCopy(mode, vertexCount, positions, texs, colors, 0, nullptr);
+ return MakeCopy(mode, vertexCount, positions, texs, colors, nullptr, nullptr);
}
struct Sizes;
@@ -50,6 +103,7 @@ public:
enum BuilderFlags {
kHasTexCoords_BuilderFlag = 1 << 0,
kHasColors_BuilderFlag = 1 << 1,
+ kHasBones_BuilderFlag = 1 << 2,
};
class Builder {
public:
@@ -61,9 +115,11 @@ public:
int vertexCount() const;
int indexCount() const;
SkPoint* positions();
- SkPoint* texCoords(); // returns null if there are no texCoords
- SkColor* colors(); // returns null if there are no colors
- uint16_t* indices(); // returns null if there are no indices
+ 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();
@@ -88,6 +144,7 @@ public:
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; }
@@ -95,6 +152,9 @@ public:
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; }
@@ -128,10 +188,12 @@ private:
uint32_t fUniqueID;
// these point inside our allocation, so none of these can be "freed"
- SkPoint* fPositions;
- SkPoint* fTexs;
- SkColor* fColors;
- uint16_t* fIndices;
+ 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;
diff --git a/include/utils/SkLuaCanvas.h b/include/utils/SkLuaCanvas.h
index 2fef2c0785..e29e0b5eb3 100644
--- a/include/utils/SkLuaCanvas.h
+++ b/include/utils/SkLuaCanvas.h
@@ -58,7 +58,8 @@ protected:
const SkPaint*, SrcRectConstraint) override;
void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
const SkPaint*) override;
- void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
+ void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+ const SkPaint&) override;
void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override;
void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override;
diff --git a/include/utils/SkNWayCanvas.h b/include/utils/SkNWayCanvas.h
index e6a6b9962e..188c0a102c 100644
--- a/include/utils/SkNWayCanvas.h
+++ b/include/utils/SkNWayCanvas.h
@@ -78,7 +78,8 @@ protected:
const SkPaint*) override;
void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
const SkPaint*) override;
- void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
+ void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+ const SkPaint&) override;
void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
int, SkBlendMode, const SkRect*, const SkPaint*) override;
void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
diff --git a/include/utils/SkNoDrawCanvas.h b/include/utils/SkNoDrawCanvas.h
index 518d090786..0e86ed65e7 100644
--- a/include/utils/SkNoDrawCanvas.h
+++ b/include/utils/SkNoDrawCanvas.h
@@ -75,7 +75,8 @@ protected:
const SkPaint*) override {}
void onDrawBitmapLattice(const SkBitmap&, const Lattice&, const SkRect&,
const SkPaint*) override {}
- void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override {}
+ void onDrawVerticesObject(const SkVertices*, const SkMatrix*, int, SkBlendMode,
+ const SkPaint&) override {}
void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
int, SkBlendMode, const SkRect*, const SkPaint*) override {}
void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override {}
diff --git a/include/utils/SkPaintFilterCanvas.h b/include/utils/SkPaintFilterCanvas.h
index 72c9784725..4728792013 100644
--- a/include/utils/SkPaintFilterCanvas.h
+++ b/include/utils/SkPaintFilterCanvas.h
@@ -88,7 +88,8 @@ protected:
const SkPaint*) override;
void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&,
const SkPaint*) override;
- void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
+ void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+ const SkPaint&) override;
void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
const SkPoint texCoords[4], SkBlendMode,
const SkPaint& paint) override;
diff --git a/resources/nima/Robot.nima b/resources/nima/Robot.nima
index af035ff1e8..c9c6af52fa 100644
--- a/resources/nima/Robot.nima
+++ b/resources/nima/Robot.nima
Binary files differ
diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp
index 2361468d56..0d1ec8ddc5 100644
--- a/src/core/SkBitmapDevice.cpp
+++ b/src/core/SkBitmapDevice.cpp
@@ -570,11 +570,12 @@ void SkBitmapDevice::drawPosText(const void* text, size_t len, const SkScalar xp
nullptr)
}
-void SkBitmapDevice::drawVertices(const SkVertices* vertices, SkBlendMode bmode,
- const SkPaint& paint) {
+void SkBitmapDevice::drawVertices(const SkVertices* vertices, const SkMatrix* bones, int boneCount,
+ SkBlendMode bmode, const SkPaint& paint) {
BDDraw(this).drawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(),
- vertices->texCoords(), vertices->colors(), bmode,
- vertices->indices(), vertices->indexCount(), paint);
+ vertices->texCoords(), vertices->colors(), vertices->boneIndices(),
+ vertices->boneWeights(), bmode, vertices->indices(),
+ vertices->indexCount(), paint, bones, boneCount);
}
void SkBitmapDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPaint& origPaint) {
diff --git a/src/core/SkBitmapDevice.h b/src/core/SkBitmapDevice.h
index ba7846ca43..e2cedaa7e1 100644
--- a/src/core/SkBitmapDevice.h
+++ b/src/core/SkBitmapDevice.h
@@ -113,7 +113,8 @@ protected:
*/
void drawPosText(const void* text, size_t len, const SkScalar pos[],
int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) override;
- void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override;
+ void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+ const SkPaint& paint) override;
void drawDevice(SkBaseDevice*, int x, int y, const SkPaint&) override;
///////////////////////////////////////////////////////////////////////////
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index b297f98156..bf32aafae9 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -1702,13 +1702,27 @@ void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
RETURN_ON_NULL(vertices);
// We expect fans to be converted to triangles when building or deserializing SkVertices.
SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
- this->onDrawVerticesObject(vertices.get(), mode, paint);
+ this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
}
void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
TRACE_EVENT0("skia", TRACE_FUNC);
RETURN_ON_NULL(vertices);
- this->onDrawVerticesObject(vertices, mode, paint);
+ this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
+}
+
+void SkCanvas::drawVertices(const sk_sp<SkVertices> vertices, const SkMatrix* bones, int boneCount,
+ SkBlendMode mode, const SkPaint& paint) {
+ TRACE_EVENT0("skia", TRACE_FUNC);
+ RETURN_ON_NULL(vertices);
+ this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
+}
+
+void SkCanvas::drawVertices(const SkVertices* vertices, const SkMatrix* bones, int boneCount,
+ SkBlendMode mode, const SkPaint& paint) {
+ TRACE_EVENT0("skia", TRACE_FUNC);
+ RETURN_ON_NULL(vertices);
+ this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
}
void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
@@ -2597,13 +2611,13 @@ void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
this->onDrawTextBlob(blob, x, y, paint);
}
-void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
- const SkPaint& paint) {
+void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
+ int boneCount, SkBlendMode bmode, const SkPaint& paint) {
LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
while (iter.next()) {
// In the common case of one iteration we could std::move vertices here.
- iter.fDevice->drawVertices(vertices, bmode, looper.paint());
+ iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
}
LOOPER_END
diff --git a/src/core/SkColorSpaceXformCanvas.cpp b/src/core/SkColorSpaceXformCanvas.cpp
index 3ef4d6d00d..caf07fb5d9 100644
--- a/src/core/SkColorSpaceXformCanvas.cpp
+++ b/src/core/SkColorSpaceXformCanvas.cpp
@@ -90,8 +90,8 @@ public:
const SkPaint& paint) override {
fTarget->drawPoints(mode, count, pts, fXformer->apply(paint));
}
- void onDrawVerticesObject(const SkVertices* vertices, SkBlendMode mode,
- const SkPaint& paint) override {
+ void onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones, int boneCount,
+ SkBlendMode mode, const SkPaint& paint) override {
sk_sp<SkVertices> copy;
if (vertices->hasColors()) {
int count = vertices->vertexCount();
@@ -99,11 +99,12 @@ public:
fXformer->apply(xformed.begin(), vertices->colors(), count);
copy = SkVertices::MakeCopy(vertices->mode(), count, vertices->positions(),
vertices->texCoords(), xformed.begin(),
+ vertices->boneIndices(), vertices->boneWeights(),
vertices->indexCount(), vertices->indices());
vertices = copy.get();
}
- fTarget->drawVertices(vertices, mode, fXformer->apply(paint));
+ fTarget->drawVertices(vertices, bones, boneCount, mode, fXformer->apply(paint));
}
void onDrawText(const void* ptr, size_t len,
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 46404b2887..08fc3e2b0d 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -137,7 +137,7 @@ void SkBaseDevice::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
auto vertices = SkPatchUtils::MakeVertices(cubics, colors, texCoords, lod.width(), lod.height(),
interpColorsLinearly);
if (vertices) {
- this->drawVertices(vertices.get(), bmode, paint);
+ this->drawVertices(vertices.get(), nullptr, 0, bmode, paint);
}
}
@@ -311,7 +311,7 @@ void SkBaseDevice::drawAtlas(const SkImage* atlas, const SkRSXform xform[],
}
SkPaint p(paint);
p.setShader(atlas->makeShader());
- this->drawVertices(builder.detach().get(), mode, p);
+ this->drawVertices(builder.detach().get(), nullptr, 0, mode, p);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/SkDevice.h b/src/core/SkDevice.h
index f840cf6218..93ed3e184a 100644
--- a/src/core/SkDevice.h
+++ b/src/core/SkDevice.h
@@ -225,7 +225,8 @@ protected:
* Decorations (underline and stike-thru) will be handled by SkCanvas.
*/
virtual void drawGlyphRun(const SkPaint& paint, SkGlyphRun* glyphRun);
- virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) = 0;
+ virtual void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+ const SkPaint&) = 0;
virtual void drawShadow(const SkPath&, const SkDrawShadowRec&);
// default implementation unrolls the blob runs.
@@ -434,7 +435,8 @@ protected:
void drawPosText(const void*, size_t, const SkScalar[], int, const SkPoint&,
const SkPaint&) override {}
void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override {}
- void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override {}
+ void drawVertices(const SkVertices*, const SkMatrix*, int, SkBlendMode,
+ const SkPaint&) override {}
private:
typedef SkBaseDevice INHERITED;
diff --git a/src/core/SkDraw.h b/src/core/SkDraw.h
index 8032ad9d3c..afd50ea229 100644
--- a/src/core/SkDraw.h
+++ b/src/core/SkDraw.h
@@ -65,11 +65,12 @@ public:
void drawPosText(const char text[], size_t byteLength,
const SkScalar pos[], int scalarsPerPosition,
const SkPoint& offset, const SkPaint&, const SkSurfaceProps*) const;
- void drawVertices(SkVertices::VertexMode mode, int count,
+ void drawVertices(SkVertices::VertexMode mode, int vertexCount,
const SkPoint vertices[], const SkPoint textures[],
- const SkColor colors[], SkBlendMode bmode,
+ const SkColor colors[], const SkVertices::BoneIndices boneIndices[],
+ const SkVertices::BoneWeights boneWeights[], SkBlendMode bmode,
const uint16_t indices[], int ptCount,
- const SkPaint& paint) const;
+ const SkPaint& paint, const SkMatrix* bones, int boneCount) const;
/**
* Overwrite the target with the path's coverage (i.e. its mask).
diff --git a/src/core/SkDraw_vertices.cpp b/src/core/SkDraw_vertices.cpp
index de6eaea5b6..f918269992 100644
--- a/src/core/SkDraw_vertices.cpp
+++ b/src/core/SkDraw_vertices.cpp
@@ -161,15 +161,16 @@ static bool compute_is_opaque(const SkColor colors[], int count) {
return SkColorGetA(c) == 0xFF;
}
-void SkDraw::drawVertices(SkVertices::VertexMode vmode, int count,
+void SkDraw::drawVertices(SkVertices::VertexMode vmode, int vertexCount,
const SkPoint vertices[], const SkPoint textures[],
- const SkColor colors[], SkBlendMode bmode,
+ const SkColor colors[], const SkVertices::BoneIndices boneIndices[],
+ const SkVertices::BoneWeights boneWeights[], SkBlendMode bmode,
const uint16_t indices[], int indexCount,
- const SkPaint& paint) const {
- SkASSERT(0 == count || vertices);
+ const SkPaint& paint, const SkMatrix* bones, int boneCount) const {
+ SkASSERT(0 == vertexCount || vertices);
// abort early if there is nothing to draw
- if (count < 3 || (indices && indexCount < 3) || fRC->isEmpty()) {
+ if (vertexCount < 3 || (indices && indexCount < 3) || fRC->isEmpty()) {
return;
}
SkMatrix ctmInv;
@@ -204,25 +205,81 @@ void SkDraw::drawVertices(SkVertices::VertexMode vmode, int count,
shader = nullptr;
}
- constexpr size_t defCount = 16;
- constexpr size_t outerSize = sizeof(SkTriColorShader) +
+ constexpr size_t kDefVertexCount = 16;
+ constexpr size_t kDefBoneCount = 8;
+ constexpr size_t kOuterSize = sizeof(SkTriColorShader) +
sizeof(SkComposeShader) +
- (sizeof(SkPoint) + sizeof(SkPM4f)) * defCount;
- SkSTArenaAlloc<outerSize> outerAlloc;
+ (2 * sizeof(SkPoint) + sizeof(SkPM4f)) * kDefVertexCount +
+ sizeof(SkMatrix) * kDefBoneCount;
+ SkSTArenaAlloc<kOuterSize> outerAlloc;
+
+ // deform vertices using the skeleton if it is passed in
+ if (bones && boneCount) {
+ // allocate space for the deformed vertices
+ SkPoint* deformed = outerAlloc.makeArray<SkPoint>(vertexCount);
+
+ // get the bone matrices
+ SkMatrix* transformedBones = outerAlloc.makeArray<SkMatrix>(boneCount);
+
+ // transform the bone matrices by the world transform
+ transformedBones[0] = bones[0];
+ for (int i = 1; i < boneCount; i ++) {
+ transformedBones[i] = SkMatrix::Concat(bones[i], bones[0]);
+ }
+
+ // deform the vertices
+ if (boneIndices && boneWeights) {
+ for (int i = 0; i < vertexCount; i ++) {
+ const SkVertices::BoneIndices& indices = boneIndices[i];
+ const SkVertices::BoneWeights& weights = boneWeights[i];
+
+ // apply bone deformations
+ SkPoint result = SkPoint::Make(0.0f, 0.0f);
+ SkPoint transformed;
+ for (uint32_t j = 0; j < 4; j ++) {
+ // get the attachment data
+ uint32_t index = indices.indices[j];
+ float weight = weights.weights[j];
+
+ // skip the bone if there is no weight
+ if (weight == 0.0f) {
+ continue;
+ }
+ SkASSERT(index != 0);
+
+ // transformed = M * v
+ transformedBones[index].mapPoints(&transformed, &vertices[i], 1);
+
+ // result += transformed * w
+ result += transformed * weight;
+ }
+
+ // set the deformed point
+ deformed[i] = result;
+ }
+ } else {
+ // no bones, so only apply world transform
+ const SkMatrix& worldTransform = bones[0];
+ worldTransform.mapPoints(deformed, vertices, vertexCount);
+ }
+
+ // change the vertices to point to deformed
+ vertices = deformed;
+ }
- SkPoint* devVerts = outerAlloc.makeArray<SkPoint>(count);
- fMatrix->mapPoints(devVerts, vertices, count);
+ SkPoint* devVerts = outerAlloc.makeArray<SkPoint>(vertexCount);
+ fMatrix->mapPoints(devVerts, vertices, vertexCount);
{
SkRect bounds;
// this also sets bounds to empty if we see a non-finite value
- bounds.set(devVerts, count);
+ bounds.set(devVerts, vertexCount);
if (bounds.isEmpty()) {
return;
}
}
- VertState state(count, indices, indexCount);
+ VertState state(vertexCount, indices, indexCount);
VertState::Proc vertProc = state.chooseProc(vmode);
if (colors || textures) {
@@ -230,10 +287,11 @@ void SkDraw::drawVertices(SkVertices::VertexMode vmode, int count,
Matrix43* matrix43 = nullptr;
if (colors) {
- dstColors = convert_colors(colors, count, fDst.colorSpace(), &outerAlloc);
+ dstColors = convert_colors(colors, vertexCount, fDst.colorSpace(), &outerAlloc);
SkTriColorShader* triShader = outerAlloc.make<SkTriColorShader>(
- compute_is_opaque(colors, count));
+ compute_is_opaque(colors,
+ vertexCount));
matrix43 = triShader->getMatrix43();
if (shader) {
shader = outerAlloc.make<SkComposeShader>(sk_ref_sp(triShader), sk_ref_sp(shader),
diff --git a/src/core/SkLiteDL.cpp b/src/core/SkLiteDL.cpp
index ce6f0d3191..4240055480 100644
--- a/src/core/SkLiteDL.cpp
+++ b/src/core/SkLiteDL.cpp
@@ -459,13 +459,17 @@ namespace {
};
struct DrawVertices final : Op {
static const auto kType = Type::DrawVertices;
- DrawVertices(const SkVertices* v, SkBlendMode m, const SkPaint& p)
- : vertices(sk_ref_sp(const_cast<SkVertices*>(v))), mode(m), paint(p) {}
+ DrawVertices(const SkVertices* v, int bc, SkBlendMode m, const SkPaint& p)
+ : vertices(sk_ref_sp(const_cast<SkVertices*>(v)))
+ , boneCount(bc)
+ , mode(m)
+ , paint(p) {}
sk_sp<SkVertices> vertices;
+ int boneCount;
SkBlendMode mode;
SkPaint paint;
void draw(SkCanvas* c, const SkMatrix&) const {
- c->drawVertices(vertices, mode, paint);
+ c->drawVertices(vertices, pod<SkMatrix>(this), boneCount, mode, paint);
}
};
struct DrawAtlas final : Op {
@@ -676,8 +680,14 @@ void SkLiteDL::drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint
void* pod = this->push<DrawPoints>(count*sizeof(SkPoint), mode, count, paint);
copy_v(pod, points,count);
}
-void SkLiteDL::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
- this->push<DrawVertices>(0, vertices, mode, paint);
+void SkLiteDL::drawVertices(const SkVertices* vertices, const SkMatrix* bones, int boneCount,
+ SkBlendMode mode, const SkPaint& paint) {
+ void* pod = this->push<DrawVertices>(boneCount * sizeof(SkMatrix),
+ vertices,
+ boneCount,
+ mode,
+ paint);
+ copy_v(pod, bones, boneCount);
}
void SkLiteDL::drawAtlas(const SkImage* atlas, const SkRSXform xforms[], const SkRect texs[],
const SkColor colors[], int count, SkBlendMode xfermode,
diff --git a/src/core/SkLiteDL.h b/src/core/SkLiteDL.h
index 6d63657084..b63ed0d514 100644
--- a/src/core/SkLiteDL.h
+++ b/src/core/SkLiteDL.h
@@ -76,7 +76,8 @@ public:
void drawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4],
SkBlendMode, const SkPaint&);
void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&);
- void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&);
+ void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+ const SkPaint&);
void drawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int,
SkBlendMode, const SkRect*, const SkPaint*);
void drawShadowRec(const SkPath&, const SkDrawShadowRec&);
diff --git a/src/core/SkLiteRecorder.cpp b/src/core/SkLiteRecorder.cpp
index bd41ff3913..0891508c92 100644
--- a/src/core/SkLiteRecorder.cpp
+++ b/src/core/SkLiteRecorder.cpp
@@ -182,9 +182,9 @@ void SkLiteRecorder::onDrawPoints(SkCanvas::PointMode mode,
const SkPaint& paint) {
fDL->drawPoints(mode, count, pts, paint);
}
-void SkLiteRecorder::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode mode,
- const SkPaint& paint) {
- fDL->drawVertices(vertices, mode, paint);
+void SkLiteRecorder::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
+ int boneCount, SkBlendMode mode, const SkPaint& paint) {
+ fDL->drawVertices(vertices, bones, boneCount, mode, paint);
}
void SkLiteRecorder::onDrawAtlas(const SkImage* atlas,
const SkRSXform xforms[],
diff --git a/src/core/SkLiteRecorder.h b/src/core/SkLiteRecorder.h
index 6b21c8984b..af538ee3aa 100644
--- a/src/core/SkLiteRecorder.h
+++ b/src/core/SkLiteRecorder.h
@@ -77,7 +77,8 @@ public:
void onDrawPatch(const SkPoint[12], const SkColor[4],
const SkPoint[4], SkBlendMode, const SkPaint&) override;
void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
- void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
+ void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+ const SkPaint&) override;
void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
int, SkBlendMode, const SkRect*, const SkPaint*) override;
void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
diff --git a/src/core/SkOverdrawCanvas.cpp b/src/core/SkOverdrawCanvas.cpp
index 25bc7fb160..b86f9a333c 100644
--- a/src/core/SkOverdrawCanvas.cpp
+++ b/src/core/SkOverdrawCanvas.cpp
@@ -219,9 +219,14 @@ void SkOverdrawCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint
fList[0]->onDrawPoints(mode, count, points, this->overdrawPaint(paint));
}
-void SkOverdrawCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode blendMode,
+void SkOverdrawCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
+ int boneCount, SkBlendMode blendMode,
const SkPaint& paint) {
- fList[0]->onDrawVerticesObject(vertices, blendMode, this->overdrawPaint(paint));
+ fList[0]->onDrawVerticesObject(vertices,
+ bones,
+ boneCount,
+ blendMode,
+ this->overdrawPaint(paint));
}
void SkOverdrawCanvas::onDrawAtlas(const SkImage* image, const SkRSXform xform[],
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index 780cb13349..f63abe724c 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -615,11 +615,15 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader,
case DRAW_VERTICES_OBJECT: {
const SkPaint* paint = fPictureData->getPaint(reader);
const SkVertices* vertices = fPictureData->getVertices(reader);
+ const int boneCount = reader->readInt();
+ const SkMatrix* bones = boneCount ?
+ (const SkMatrix*) reader->skip(boneCount, sizeof(SkMatrix)) :
+ nullptr;
SkBlendMode bmode = reader->read32LE(SkBlendMode::kLastMode);
BREAK_ON_READ_ERROR(reader);
if (paint && vertices) {
- canvas->drawVertices(vertices, bmode, *paint);
+ canvas->drawVertices(vertices, bones, boneCount, bmode, *paint);
}
} break;
case RESTORE:
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index 87c8c4d2fb..922fb6a425 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -682,14 +682,16 @@ void SkPictureRecord::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matri
this->validate(initialOffset, size);
}
-void SkPictureRecord::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode mode,
- const SkPaint& paint) {
- // op + paint index + vertices index + mode
- size_t size = 4 * kUInt32Size;
+void SkPictureRecord::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
+ int boneCount, SkBlendMode mode, const SkPaint& paint) {
+ // op + paint index + vertices index + number of bones + bone matrices + mode
+ size_t size = 5 * kUInt32Size + boneCount * sizeof(SkMatrix);
size_t initialOffset = this->addDraw(DRAW_VERTICES_OBJECT, &size);
this->addPaint(paint);
this->addVertices(vertices);
+ this->addInt(boneCount);
+ fWriter.write(bones, boneCount * sizeof(SkMatrix));
this->addInt(static_cast<uint32_t>(mode));
this->validate(initialOffset, size);
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index ad2dbdfd24..dc9f4d9bdc 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -196,7 +196,8 @@ protected:
void onDrawImageLattice(const SkImage*, const SkCanvas::Lattice& lattice, const SkRect& dst,
const SkPaint*) override;
void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
- void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
+ void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+ const SkPaint&) override;
void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override;
void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override;
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index f712c0e436..9c58456295 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -126,7 +126,7 @@ DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, &r.matrix, r.p
DRAW(DrawTextRSXform, drawTextRSXform(r.text, r.byteLength, r.xforms, r.cull, r.paint));
DRAW(DrawAtlas, drawAtlas(r.atlas.get(),
r.xforms, r.texs, r.colors, r.count, r.mode, r.cull, r.paint));
-DRAW(DrawVertices, drawVertices(r.vertices, r.bmode, r.paint));
+DRAW(DrawVertices, drawVertices(r.vertices, r.bones, r.boneCount, r.bmode, r.paint));
DRAW(DrawShadowRec, private_draw_shadow_rec(r.path, r.rec));
DRAW(DrawAnnotation, drawAnnotation(r.rect, r.key.c_str(), r.value.get()));
#undef DRAW
diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp
index 65dcd7bb4b..1abd5823af 100644
--- a/src/core/SkRecorder.cpp
+++ b/src/core/SkRecorder.cpp
@@ -317,9 +317,13 @@ void SkRecorder::onDrawPicture(const SkPicture* pic, const SkMatrix* matrix, con
}
}
-void SkRecorder::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
- const SkPaint& paint) {
- this->append<SkRecords::DrawVertices>(paint, sk_ref_sp(const_cast<SkVertices*>(vertices)), bmode);
+void SkRecorder::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
+ int boneCount, SkBlendMode bmode, const SkPaint& paint) {
+ this->append<SkRecords::DrawVertices>(paint,
+ sk_ref_sp(const_cast<SkVertices*>(vertices)),
+ this->copy(bones, boneCount),
+ boneCount,
+ bmode);
}
void SkRecorder::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h
index 6a7a83bdc2..7fed8eaacc 100644
--- a/src/core/SkRecorder.h
+++ b/src/core/SkRecorder.h
@@ -121,7 +121,8 @@ public:
const SkPaint*) override;
void onDrawBitmapLattice(const SkBitmap&, const Lattice& lattice, const SkRect& dst,
const SkPaint*) override;
- void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
+ void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+ const SkPaint&) override;
void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
int count, SkBlendMode, const SkRect* cull, const SkPaint*) override;
void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
diff --git a/src/core/SkRecords.h b/src/core/SkRecords.h
index 67424aca2a..4ec2ae68c7 100644
--- a/src/core/SkRecords.h
+++ b/src/core/SkRecords.h
@@ -344,6 +344,8 @@ RECORD(DrawAtlas, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag,
RECORD(DrawVertices, kDraw_Tag|kHasPaint_Tag,
SkPaint paint;
sk_sp<SkVertices> vertices;
+ PODArray<SkMatrix> bones;
+ int boneCount;
SkBlendMode bmode);
RECORD(DrawShadowRec, kDraw_Tag,
PreCachedPath path;
diff --git a/src/core/SkThreadedBMPDevice.cpp b/src/core/SkThreadedBMPDevice.cpp
index 10cd824205..de2b6c0230 100644
--- a/src/core/SkThreadedBMPDevice.cpp
+++ b/src/core/SkThreadedBMPDevice.cpp
@@ -222,15 +222,16 @@ void SkThreadedBMPDevice::drawPosText(const void* text, size_t len, const SkScal
});
}
-void SkThreadedBMPDevice::drawVertices(const SkVertices* vertices, SkBlendMode bmode,
- const SkPaint& paint) {
+void SkThreadedBMPDevice::drawVertices(const SkVertices* vertices, const SkMatrix* bones,
+ int boneCount, SkBlendMode bmode, const SkPaint& paint) {
const sk_sp<SkVertices> verts = sk_ref_sp(vertices); // retain vertices until flush
SkRect drawBounds = SkRectPriv::MakeLargest(); // TODO tighter drawBounds
fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
TileDraw(ds, tileBounds).drawVertices(verts->mode(), verts->vertexCount(),
verts->positions(), verts->texCoords(),
- verts->colors(), bmode, verts->indices(),
- verts->indexCount(), paint);
+ verts->colors(), verts->boneIndices(),
+ verts->boneWeights(), bmode, verts->indices(),
+ verts->indexCount(), paint, bones, boneCount);
});
}
diff --git a/src/core/SkThreadedBMPDevice.h b/src/core/SkThreadedBMPDevice.h
index 13d837424c..0cfb91db07 100644
--- a/src/core/SkThreadedBMPDevice.h
+++ b/src/core/SkThreadedBMPDevice.h
@@ -35,7 +35,8 @@ protected:
void drawSprite(const SkBitmap&, int x, int y, const SkPaint&) override;
void drawPosText(const void* text, size_t len, const SkScalar pos[],
int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) override;
- void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override;
+ void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+ const SkPaint&) override;
void drawBitmap(const SkBitmap&, const SkMatrix&, const SkRect* dstOrNull,
const SkPaint&) override;
diff --git a/src/core/SkVertices.cpp b/src/core/SkVertices.cpp
index d4c6ed56de..04db0d35fb 100644
--- a/src/core/SkVertices.cpp
+++ b/src/core/SkVertices.cpp
@@ -27,12 +27,14 @@ static int32_t next_id() {
struct SkVertices::Sizes {
Sizes(SkVertices::VertexMode mode, int vertexCount, int indexCount, bool hasTexs,
- bool hasColors) {
+ bool hasColors, bool hasBones) {
SkSafeMath safe;
fVSize = safe.mul(vertexCount, sizeof(SkPoint));
fTSize = hasTexs ? safe.mul(vertexCount, sizeof(SkPoint)) : 0;
fCSize = hasColors ? safe.mul(vertexCount, sizeof(SkColor)) : 0;
+ fBISize = hasBones ? safe.mul(vertexCount, sizeof(BoneIndices)) : 0;
+ fBWSize = hasBones ? safe.mul(vertexCount, sizeof(BoneWeights)) : 0;
fBuilderTriFanISize = 0;
fISize = safe.mul(indexCount, sizeof(uint16_t));
@@ -61,7 +63,9 @@ struct SkVertices::Sizes {
safe.add(fVSize,
safe.add(fTSize,
safe.add(fCSize,
- fISize))));
+ safe.add(fBISize,
+ safe.add(fBWSize,
+ fISize))))));
if (safe.ok()) {
fArrays = fTotal - sizeof(SkVertices); // just the sum of the arrays
@@ -73,10 +77,12 @@ struct SkVertices::Sizes {
bool isValid() const { return fTotal != 0; }
size_t fTotal; // size of entire SkVertices allocation (obj + arrays)
- size_t fArrays; // size of all the arrays (V + T + C + I)
+ size_t fArrays; // size of all the arrays (V + T + C + BI + BW + I)
size_t fVSize;
size_t fTSize;
size_t fCSize;
+ size_t fBISize;
+ size_t fBWSize;
size_t fISize;
// For indexed tri-fans this is the number of amount of space fo indices needed in the builder
@@ -88,8 +94,9 @@ SkVertices::Builder::Builder(VertexMode mode, int vertexCount, int indexCount,
uint32_t builderFlags) {
bool hasTexs = SkToBool(builderFlags & SkVertices::kHasTexCoords_BuilderFlag);
bool hasColors = SkToBool(builderFlags & SkVertices::kHasColors_BuilderFlag);
+ bool hasBones = SkToBool(builderFlags & SkVertices::kHasBones_BuilderFlag);
this->init(mode, vertexCount, indexCount,
- SkVertices::Sizes(mode, vertexCount, indexCount, hasTexs, hasColors));
+ SkVertices::Sizes(mode, vertexCount, indexCount, hasTexs, hasColors, hasBones));
}
SkVertices::Builder::Builder(VertexMode mode, int vertexCount, int indexCount,
@@ -113,13 +120,16 @@ void SkVertices::Builder::init(VertexMode mode, int vertexCount, int indexCount,
// need to point past the object to store the arrays
char* ptr = (char*)storage + sizeof(SkVertices);
- fVertices->fPositions = (SkPoint*)ptr; ptr += sizes.fVSize;
- fVertices->fTexs = sizes.fTSize ? (SkPoint*)ptr : nullptr; ptr += sizes.fTSize;
- fVertices->fColors = sizes.fCSize ? (SkColor*)ptr : nullptr; ptr += sizes.fCSize;
+ fVertices->fPositions = (SkPoint*)ptr; ptr += sizes.fVSize;
+ fVertices->fTexs = sizes.fTSize ? (SkPoint*)ptr : nullptr; ptr += sizes.fTSize;
+ fVertices->fColors = sizes.fCSize ? (SkColor*)ptr : nullptr; ptr += sizes.fCSize;
+ fVertices->fBoneIndices = sizes.fBISize ? (BoneIndices*) ptr : nullptr; ptr += sizes.fBISize;
+ fVertices->fBoneWeights = sizes.fBWSize ? (BoneWeights*) ptr : nullptr; ptr += sizes.fBWSize;
fVertices->fIndices = sizes.fISize ? (uint16_t*)ptr : nullptr;
fVertices->fVertexCnt = vertexCount;
fVertices->fIndexCnt = indexCount;
fVertices->fMode = mode;
+
// We defer assigning fBounds and fUniqueID until detach() is called
}
@@ -173,6 +183,14 @@ SkColor* SkVertices::Builder::colors() {
return fVertices ? const_cast<SkColor*>(fVertices->colors()) : nullptr;
}
+SkVertices::BoneIndices* SkVertices::Builder::boneIndices() {
+ return fVertices ? const_cast<BoneIndices*>(fVertices->boneIndices()) : nullptr;
+}
+
+SkVertices::BoneWeights* SkVertices::Builder::boneWeights() {
+ return fVertices ? const_cast<BoneWeights*>(fVertices->boneWeights()) : nullptr;
+}
+
uint16_t* SkVertices::Builder::indices() {
if (!fVertices) {
return nullptr;
@@ -187,9 +205,17 @@ uint16_t* SkVertices::Builder::indices() {
sk_sp<SkVertices> SkVertices::MakeCopy(VertexMode mode, int vertexCount,
const SkPoint pos[], const SkPoint texs[],
- const SkColor colors[], int indexCount,
- const uint16_t indices[]) {
- Sizes sizes(mode, vertexCount, indexCount, texs != nullptr, colors != nullptr);
+ const SkColor colors[],
+ const BoneIndices boneIndices[],
+ const BoneWeights boneWeights[],
+ int indexCount, const uint16_t indices[]) {
+ SkASSERT((!boneIndices && !boneWeights) || (boneIndices && boneWeights));
+ Sizes sizes(mode,
+ vertexCount,
+ indexCount,
+ texs != nullptr,
+ colors != nullptr,
+ boneIndices != nullptr);
if (!sizes.isValid()) {
return nullptr;
}
@@ -200,6 +226,8 @@ sk_sp<SkVertices> SkVertices::MakeCopy(VertexMode mode, int vertexCount,
sk_careful_memcpy(builder.positions(), pos, sizes.fVSize);
sk_careful_memcpy(builder.texCoords(), texs, sizes.fTSize);
sk_careful_memcpy(builder.colors(), colors, sizes.fCSize);
+ sk_careful_memcpy(builder.boneIndices(), boneIndices, sizes.fBISize);
+ sk_careful_memcpy(builder.boneWeights(), boneWeights, sizes.fBWSize);
size_t isize = (mode == kTriangleFan_VertexMode) ? sizes.fBuilderTriFanISize : sizes.fISize;
sk_careful_memcpy(builder.indices(), indices, isize);
@@ -207,19 +235,26 @@ sk_sp<SkVertices> SkVertices::MakeCopy(VertexMode mode, int vertexCount,
}
size_t SkVertices::approximateSize() const {
- Sizes sizes(fMode, fVertexCnt, fIndexCnt, this->hasTexCoords(), this->hasColors());
+ Sizes sizes(fMode,
+ fVertexCnt,
+ fIndexCnt,
+ this->hasTexCoords(),
+ this->hasColors(),
+ this->hasBones());
SkASSERT(sizes.isValid());
return sizeof(SkVertices) + sizes.fArrays;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
-// storage = packed | vertex_count | index_count | pos[] | texs[] | colors[] | indices[]
+// storage = packed | vertex_count | index_count | pos[] | texs[] | colors[] | boneIndices[] |
+// boneWeights[] | indices[]
// = header + arrays
#define kMode_Mask 0x0FF
#define kHasTexs_Mask 0x100
#define kHasColors_Mask 0x200
+#define kHasBones_Mask 0x400
#define kHeaderSize (3 * sizeof(uint32_t))
sk_sp<SkData> SkVertices::encode() const {
@@ -232,8 +267,16 @@ sk_sp<SkData> SkVertices::encode() const {
if (this->hasColors()) {
packed |= kHasColors_Mask;
}
+ if (this->hasBones()) {
+ packed |= kHasBones_Mask;
+ }
- Sizes sizes(fMode, fVertexCnt, fIndexCnt, this->hasTexCoords(), this->hasColors());
+ Sizes sizes(fMode,
+ fVertexCnt,
+ fIndexCnt,
+ this->hasTexCoords(),
+ this->hasColors(),
+ this->hasBones());
SkASSERT(sizes.isValid());
SkASSERT(!sizes.fBuilderTriFanISize);
// need to force alignment to 4 for SkWriter32 -- will pad w/ 0s as needed
@@ -248,6 +291,8 @@ sk_sp<SkData> SkVertices::encode() const {
writer.write(fPositions, sizes.fVSize);
writer.write(fTexs, sizes.fTSize);
writer.write(fColors, sizes.fCSize);
+ writer.write(fBoneIndices, sizes.fBISize);
+ writer.write(fBoneWeights, sizes.fBWSize);
// if index-count is odd, we won't be 4-bytes aligned, so we call the pad version
writer.writePad(fIndices, sizes.fISize);
@@ -272,7 +317,8 @@ sk_sp<SkVertices> SkVertices::Decode(const void* data, size_t length) {
}
const bool hasTexs = SkToBool(packed & kHasTexs_Mask);
const bool hasColors = SkToBool(packed & kHasColors_Mask);
- Sizes sizes(mode, vertexCount, indexCount, hasTexs, hasColors);
+ const bool hasBones = SkToBool(packed & kHasBones_Mask);
+ Sizes sizes(mode, vertexCount, indexCount, hasTexs, hasColors, hasBones);
if (!sizes.isValid()) {
return nullptr;
}
@@ -286,6 +332,8 @@ sk_sp<SkVertices> SkVertices::Decode(const void* data, size_t length) {
reader.read(builder.positions(), sizes.fVSize);
reader.read(builder.texCoords(), sizes.fTSize);
reader.read(builder.colors(), sizes.fCSize);
+ reader.read(builder.boneIndices(), sizes.fBISize);
+ reader.read(builder.boneWeights(), sizes.fBWSize);
size_t isize = (mode == kTriangleFan_VertexMode) ? sizes.fBuilderTriFanISize : sizes.fISize;
reader.read(builder.indices(), isize);
if (indexCount > 0) {
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 819acd2ef8..a665517d4f 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1541,7 +1541,9 @@ void SkGpuDevice::wireframeVertices(SkVertices::VertexMode vmode, int vertexCoun
&primitiveType);
}
-void SkGpuDevice::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
+void SkGpuDevice::drawVertices(const SkVertices* vertices, const SkMatrix* bones, int boneCount,
+ SkBlendMode mode, const SkPaint& paint) {
+ // TODO: GPU ANIMATION
ASSERT_SINGLE_OWNER
GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawVertices", fContext.get());
diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h
index 7c7030e1ab..48ba8ac8a1 100644
--- a/src/gpu/SkGpuDevice.h
+++ b/src/gpu/SkGpuDevice.h
@@ -91,7 +91,8 @@ public:
int scalarsPerPos, const SkPoint& offset, const SkPaint&) override;
void drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y,
const SkPaint& paint, SkDrawFilter* drawFilter) override;
- void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override;
+ void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+ const SkPaint&) override;
void drawShadow(const SkPath&, const SkDrawShadowRec&) override;
void drawAtlas(const SkImage* atlas, const SkRSXform[], const SkRect[],
const SkColor[], int count, SkBlendMode, const SkPaint&) override;
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 45a9b95915..2d2e27bf1f 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -1473,7 +1473,8 @@ void SkPDFDevice::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
}
}
-void SkPDFDevice::drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) {
+void SkPDFDevice::drawVertices(const SkVertices*, const SkMatrix*, int, SkBlendMode,
+ const SkPaint&) {
if (this->hasEmptyClip()) {
return;
}
diff --git a/src/pdf/SkPDFDevice.h b/src/pdf/SkPDFDevice.h
index 33d0e70e67..4c9c9c88ac 100644
--- a/src/pdf/SkPDFDevice.h
+++ b/src/pdf/SkPDFDevice.h
@@ -100,7 +100,8 @@ public:
const SkPoint& offset, const SkPaint&) override;
void drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y,
const SkPaint &, SkDrawFilter*) override;
- void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override;
+ void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+ const SkPaint&) override;
void drawDevice(SkBaseDevice*, int x, int y,
const SkPaint&) override;
diff --git a/src/pipe/SkPipeCanvas.cpp b/src/pipe/SkPipeCanvas.cpp
index d66953c5bd..aabff5bfae 100644
--- a/src/pipe/SkPipeCanvas.cpp
+++ b/src/pipe/SkPipeCanvas.cpp
@@ -728,14 +728,16 @@ void SkPipeCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
write_paint(writer, paint, kGeometry_PaintUsage);
}
-void SkPipeCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
- const SkPaint& paint) {
+void SkPipeCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
+ int boneCount, SkBlendMode bmode, const SkPaint& paint) {
unsigned extra = static_cast<unsigned>(bmode);
SkPipeWriter writer(this);
writer.write32(pack_verb(SkPipeVerb::kDrawVertices, extra));
// TODO: dedup vertices?
writer.writeDataAsByteArray(vertices->encode().get());
+ writer.write32(boneCount);
+ writer.write(bones, sizeof(SkMatrix) * boneCount);
write_paint(writer, paint, kVertices_PaintUsage);
}
diff --git a/src/pipe/SkPipeCanvas.h b/src/pipe/SkPipeCanvas.h
index 65bca4dfc4..b39f80920b 100644
--- a/src/pipe/SkPipeCanvas.h
+++ b/src/pipe/SkPipeCanvas.h
@@ -135,7 +135,8 @@ protected:
const SkPaint*) override;
void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst,
const SkPaint*) override;
- void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
+ void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+ const SkPaint&) override;
void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override;
void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override;
diff --git a/src/pipe/SkPipeReader.cpp b/src/pipe/SkPipeReader.cpp
index ada4a21342..312e3da4e8 100644
--- a/src/pipe/SkPipeReader.cpp
+++ b/src/pipe/SkPipeReader.cpp
@@ -562,9 +562,14 @@ static void drawImageLattice_handler(SkPipeReader& reader, uint32_t packedVerb,
static void drawVertices_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) {
SkASSERT(SkPipeVerb::kDrawVertices == unpack_verb(packedVerb));
SkBlendMode bmode = (SkBlendMode)unpack_verb_extra(packedVerb);
+ sk_sp<SkVertices> vertices = nullptr;
if (sk_sp<SkData> data = reader.readByteArrayAsData()) {
- canvas->drawVertices(SkVertices::Decode(data->data(), data->size()), bmode,
- read_paint(reader));
+ vertices = SkVertices::Decode(data->data(), data->size());
+ }
+ int boneCount = reader.read32();
+ const SkMatrix* bones = boneCount ? reader.skipT<SkMatrix>(boneCount) : nullptr;
+ if (vertices) {
+ canvas->drawVertices(vertices, bones, boneCount, bmode, read_paint(reader));
}
}
diff --git a/src/svg/SkSVGDevice.cpp b/src/svg/SkSVGDevice.cpp
index d552803e73..c2a402f695 100644
--- a/src/svg/SkSVGDevice.cpp
+++ b/src/svg/SkSVGDevice.cpp
@@ -988,7 +988,8 @@ void SkSVGDevice::drawTextOnPath(const void* text, size_t len, const SkPath& pat
}
}
-void SkSVGDevice::drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) {
+void SkSVGDevice::drawVertices(const SkVertices*, const SkMatrix*, int, SkBlendMode,
+ const SkPaint&) {
// todo
}
diff --git a/src/svg/SkSVGDevice.h b/src/svg/SkSVGDevice.h
index 4784c7e238..6b8ee4ff44 100644
--- a/src/svg/SkSVGDevice.h
+++ b/src/svg/SkSVGDevice.h
@@ -43,7 +43,8 @@ protected:
void drawTextOnPath(const void* text, size_t len,
const SkPath& path, const SkMatrix* matrix,
const SkPaint& paint) override;
- void drawVertices(const SkVertices*, SkBlendMode, const SkPaint& paint) override;
+ void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+ const SkPaint& paint) override;
void drawDevice(SkBaseDevice*, int x, int y,
const SkPaint&) override;
diff --git a/src/utils/SkLuaCanvas.cpp b/src/utils/SkLuaCanvas.cpp
index c7e3064c9b..441857f664 100644
--- a/src/utils/SkLuaCanvas.cpp
+++ b/src/utils/SkLuaCanvas.cpp
@@ -314,7 +314,8 @@ void SkLuaCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
this->INHERITED::onDrawDrawable(drawable, matrix);
}
-void SkLuaCanvas::onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint& paint) {
+void SkLuaCanvas::onDrawVerticesObject(const SkVertices*, const SkMatrix*, int, SkBlendMode,
+ const SkPaint& paint) {
AUTO_LUA("drawVertices");
lua.pushPaint(paint, "paint");
}
diff --git a/src/utils/SkNWayCanvas.cpp b/src/utils/SkNWayCanvas.cpp
index c9f9768e7c..017ec0551b 100644
--- a/src/utils/SkNWayCanvas.cpp
+++ b/src/utils/SkNWayCanvas.cpp
@@ -320,11 +320,11 @@ void SkNWayCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix)
}
}
-void SkNWayCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
- const SkPaint& paint) {
+void SkNWayCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
+ int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Iter iter(fList);
while (iter.next()) {
- iter->drawVertices(vertices, bmode, paint);
+ iter->drawVertices(vertices, bones, boneCount, bmode, paint);
}
}
diff --git a/src/utils/SkPaintFilterCanvas.cpp b/src/utils/SkPaintFilterCanvas.cpp
index c17990d536..929488caea 100644
--- a/src/utils/SkPaintFilterCanvas.cpp
+++ b/src/utils/SkPaintFilterCanvas.cpp
@@ -173,11 +173,12 @@ void SkPaintFilterCanvas::onDrawImageLattice(const SkImage* image, const Lattice
}
}
-void SkPaintFilterCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
+void SkPaintFilterCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
+ int boneCount, SkBlendMode bmode,
const SkPaint& paint) {
AutoPaintFilter apf(this, kVertices_Type, paint);
if (apf.shouldDraw()) {
- this->SkNWayCanvas::onDrawVerticesObject(vertices, bmode, *apf.paint());
+ this->SkNWayCanvas::onDrawVerticesObject(vertices, bones, boneCount, bmode, *apf.paint());
}
}
diff --git a/src/utils/SkShadowUtils.cpp b/src/utils/SkShadowUtils.cpp
index 6d5b7e16b4..c6b92ad985 100644
--- a/src/utils/SkShadowUtils.cpp
+++ b/src/utils/SkShadowUtils.cpp
@@ -545,7 +545,7 @@ void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
if (vertices->vertexCount()) {
SkAutoDeviceCTMRestore adr(this, SkMatrix::Concat(this->ctm(),
SkMatrix::MakeTrans(tx, ty)));
- this->drawVertices(vertices, mode, paint);
+ this->drawVertices(vertices, nullptr, 0, mode, paint);
}
};
@@ -580,7 +580,7 @@ void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
SkColorFilter::MakeModeFilter(rec.fAmbientColor,
SkBlendMode::kModulate)->makeComposed(
SkGaussianColorFilter::Make()));
- this->drawVertices(vertices.get(), SkBlendMode::kModulate, paint);
+ this->drawVertices(vertices.get(), nullptr, 0, SkBlendMode::kModulate, paint);
success = true;
}
}
@@ -661,7 +661,7 @@ void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
SkColorFilter::MakeModeFilter(rec.fSpotColor,
SkBlendMode::kModulate)->makeComposed(
SkGaussianColorFilter::Make()));
- this->drawVertices(vertices.get(), SkBlendMode::kModulate, paint);
+ this->drawVertices(vertices.get(), nullptr, 0, SkBlendMode::kModulate, paint);
success = true;
}
}
diff --git a/src/xps/SkXPSDevice.cpp b/src/xps/SkXPSDevice.cpp
index 36d1bd171f..797ff38483 100644
--- a/src/xps/SkXPSDevice.cpp
+++ b/src/xps/SkXPSDevice.cpp
@@ -1156,9 +1156,11 @@ void SkXPSDevice::drawPoints(SkCanvas::PointMode mode,
draw(this, &SkDraw::drawPoints, mode, count, points, paint, this);
}
-void SkXPSDevice::drawVertices(const SkVertices* v, SkBlendMode blendMode, const SkPaint& paint) {
+void SkXPSDevice::drawVertices(const SkVertices* v, const SkMatrix* bones, int boneCount,
+ SkBlendMode blendMode, const SkPaint& paint) {
draw(this, &SkDraw::drawVertices, v->mode(), v->vertexCount(), v->positions(), v->texCoords(),
- v->colors(), blendMode, v->indices(), v->indexCount(), paint);
+ v->colors(), v->boneIndices(), v->boneWeights(), blendMode, v->indices(), v->indexCount(),
+ paint, bones, boneCount);
}
void SkXPSDevice::drawPaint(const SkPaint& origPaint) {
diff --git a/src/xps/SkXPSDevice.h b/src/xps/SkXPSDevice.h
index 81e881ea82..03de5f1dcb 100644
--- a/src/xps/SkXPSDevice.h
+++ b/src/xps/SkXPSDevice.h
@@ -100,7 +100,8 @@ protected:
void drawPosText(const void* text, size_t len,
const SkScalar pos[], int scalarsPerPos,
const SkPoint& offset, const SkPaint& paint) override;
- void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override;
+ void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+ const SkPaint&) override;
void drawDevice(SkBaseDevice*, int x, int y,
const SkPaint&) override;
diff --git a/tools/debugger/SkDebugCanvas.cpp b/tools/debugger/SkDebugCanvas.cpp
index 8026eed479..537bcb1bf9 100644
--- a/tools/debugger/SkDebugCanvas.cpp
+++ b/tools/debugger/SkDebugCanvas.cpp
@@ -445,8 +445,9 @@ void SkDebugCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4
this->addDrawCommand(new SkDrawPatchCommand(cubics, colors, texCoords, bmode, paint));
}
-void SkDebugCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
- const SkPaint& paint) {
+void SkDebugCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
+ int boneCount, SkBlendMode bmode, const SkPaint& paint) {
+ // TODO: ANIMATION NOT LOGGED
this->addDrawCommand(new SkDrawVerticesCommand(sk_ref_sp(const_cast<SkVertices*>(vertices)),
bmode, paint));
}
diff --git a/tools/debugger/SkDebugCanvas.h b/tools/debugger/SkDebugCanvas.h
index c4a61e7887..b95614931b 100644
--- a/tools/debugger/SkDebugCanvas.h
+++ b/tools/debugger/SkDebugCanvas.h
@@ -146,7 +146,8 @@ protected:
void onDrawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&) override;
void onDrawRRect(const SkRRect&, const SkPaint&) override;
void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
- void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
+ void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+ const SkPaint&) override;
void onDrawPath(const SkPath&, const SkPaint&) override;
void onDrawRegion(const SkRegion&, const SkPaint&) override;
void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override;
diff --git a/tools/flags/SkCommonFlags.cpp b/tools/flags/SkCommonFlags.cpp
index 73b0eb4f12..ed4d169585 100644
--- a/tools/flags/SkCommonFlags.cpp
+++ b/tools/flags/SkCommonFlags.cpp
@@ -57,10 +57,12 @@ DEFINE_bool(disableDriverCorrectnessWorkarounds, false, "Disables all GPU driver
DEFINE_string(skps, "/data/local/tmp/skps", "Directory to read skps from.");
DEFINE_string(jpgs, "/data/local/tmp/resources", "Directory to read jpgs from.");
DEFINE_string(jsons, "/data/local/tmp/jsons", "Directory to read (Bodymovin) jsons from.");
+DEFINE_string(nimas, "/data/local/tmp/nimas", "Directory to read NIMA animations from.");
#else
DEFINE_string(skps, "skps", "Directory to read skps from.");
DEFINE_string(jpgs, "jpgs", "Directory to read jpgs from.");
DEFINE_string(jsons, "jsons", "Directory to read (Bodymovin) jsons from.");
+DEFINE_string(nimas, "nimas", "Directory to read NIMA animations from.");
#endif
DEFINE_int32(skpViewportSize, 1000, "Width & height of the viewport used to crop skp rendering.");
diff --git a/tools/flags/SkCommonFlags.h b/tools/flags/SkCommonFlags.h
index 3dca16f36d..10f90c0293 100644
--- a/tools/flags/SkCommonFlags.h
+++ b/tools/flags/SkCommonFlags.h
@@ -28,6 +28,7 @@ DECLARE_int32(skpViewportSize);
DECLARE_string(jpgs);
DECLARE_string(jsons);
DECLARE_string(svgs);
+DECLARE_string(nimas);
DECLARE_bool(nativeFonts);
DECLARE_int32(threads);
DECLARE_string(resourcePath);
diff --git a/tools/viewer/NIMASlide.cpp b/tools/viewer/NIMASlide.cpp
new file mode 100644
index 0000000000..c13ff2f11d
--- /dev/null
+++ b/tools/viewer/NIMASlide.cpp
@@ -0,0 +1,516 @@
+/*
+* Copyright 2018 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#include "NIMASlide.h"
+
+#include "SkAnimTimer.h"
+#include "SkOSPath.h"
+#include "Resources.h"
+#include "imgui.h"
+
+#include <algorithm>
+#include <cmath>
+
+using namespace sk_app;
+using namespace nima;
+
+// NIMA stores its matrices as 6 floats to represent translation and scale. This function takes
+// that format and converts it into a 3x3 matrix representation.
+static void nima_to_skmatrix(const float* nimaData, SkMatrix& matrix) {
+ matrix[0] = nimaData[0];
+ matrix[1] = nimaData[2];
+ matrix[2] = nimaData[4];
+ matrix[3] = nimaData[1];
+ matrix[4] = nimaData[3];
+ matrix[5] = nimaData[5];
+ matrix[6] = 0.0f;
+ matrix[7] = 0.0f;
+ matrix[8] = 1.0f;
+}
+
+// ImGui expects an array of const char* when displaying a ListBox. This function is for an
+// overload of ImGui::ListBox that takes a getter so that ListBox works with
+// std::vector<std::string>.
+static bool vector_getter(void* v, int index, const char** out) {
+ auto vector = reinterpret_cast<std::vector<std::string>*>(v);
+ *out = vector->at(index).c_str();
+ return true;
+}
+
+// A wrapper class that handles rendering of ActorImages (renderable components NIMA Actors).
+class NIMAActorImage {
+public:
+ NIMAActorImage(ActorImage* actorImage, SkImage* texture, SkPaint* paint)
+ : fActorImage(actorImage)
+ , fTexture(texture)
+ , fPaint(paint)
+ , fSkinned(false)
+ , fPositions()
+ , fTexs()
+ , fBoneIdx()
+ , fBoneWgt()
+ , fIndices()
+ , fBones()
+ , fVertices(nullptr)
+ , fRenderMode(kBackend_RenderMode) {
+ // Update the vertices and bones.
+ this->updateVertices();
+ this->updateBones();
+
+ // Update the vertices object.
+ this->updateVerticesObject(false);
+ }
+
+ void renderBackend(SkCanvas* canvas) {
+ // Reset vertices if the render mode has changed.
+ if (fRenderMode != kBackend_RenderMode) {
+ fRenderMode = kBackend_RenderMode;
+ this->updateVertices();
+ this->updateVerticesObject(false);
+ }
+
+ canvas->save();
+
+ // Update the vertex data.
+ if (fActorImage->doesAnimationVertexDeform() && fActorImage->isVertexDeformDirty()) {
+ this->updateVertices();
+ this->updateVerticesObject(false);
+ fActorImage->isVertexDeformDirty(false);
+ }
+
+ // Update the bones.
+ this->updateBones();
+
+ // Draw the vertices object.
+ this->drawVerticesObject(canvas, true);
+
+ canvas->restore();
+ }
+
+ void renderImmediate(SkCanvas* canvas) {
+ // Reset vertices if the render mode has changed.
+ if (fRenderMode != kImmediate_RenderMode) {
+ fRenderMode = kImmediate_RenderMode;
+ this->updateVertices();
+ this->updateVerticesObject(true);
+ }
+
+ // Update the vertex data.
+ if (fActorImage->doesAnimationVertexDeform() && fActorImage->isVertexDeformDirty()) {
+ this->updateVertices();
+ fActorImage->isVertexDeformDirty(false);
+ }
+
+ // Update the vertices object.
+ this->updateVerticesObject(true);
+
+ // Draw the vertices object.
+ this->drawVerticesObject(canvas, false);
+ }
+
+ int drawOrder() const { return fActorImage->drawOrder(); }
+
+private:
+ void updateVertices() {
+ // Update whether the image is skinned.
+ fSkinned = fActorImage->connectedBoneCount() > 0;
+
+ // Retrieve data from the image.
+ uint32_t vertexCount = fActorImage->vertexCount();
+ uint32_t vertexStride = fActorImage->vertexStride();
+ float* vertexData = fActorImage->vertices();
+ uint32_t indexCount = fActorImage->triangleCount() * 3;
+ uint16_t* indexData = fActorImage->triangles();
+
+ // Don't render if not visible.
+ if (!vertexCount || fActorImage->textureIndex() < 0) {
+ fPositions.clear();
+ fTexs.clear();
+ fBoneIdx.clear();
+ fBoneWgt.clear();
+ fIndices.clear();
+ return;
+ }
+
+ // Split the vertex data.
+ fPositions.resize(vertexCount);
+ fTexs.resize(vertexCount);
+ fIndices.resize(indexCount);
+ if (fSkinned) {
+ fBoneIdx.resize(vertexCount * 4);
+ fBoneWgt.resize(vertexCount * 4);
+ }
+ for (uint32_t i = 0; i < vertexCount; i ++) {
+ uint32_t j = i * vertexStride;
+
+ // Get the attributes.
+ float* attrPosition = vertexData + j;
+ float* attrTex = vertexData + j + 2;
+ float* attrBoneIdx = vertexData + j + 4;
+ float* attrBoneWgt = vertexData + j + 8;
+
+ // Get deformed positions if necessary.
+ if (fActorImage->doesAnimationVertexDeform()) {
+ attrPosition = fActorImage->animationDeformedVertices() + i * 2;
+ }
+
+ // Set the data.
+ fPositions[i].set(attrPosition[0], attrPosition[1]);
+ fTexs[i].set(attrTex[0] * fTexture->width(), attrTex[1] * fTexture->height());
+ if (fSkinned) {
+ for (uint32_t k = 0; k < 4; k ++) {
+ fBoneIdx[i].indices[k] = static_cast<uint32_t>(attrBoneIdx[k]);
+ fBoneWgt[i].weights[k] = attrBoneWgt[k];
+ }
+ }
+ }
+ memcpy(fIndices.data(), indexData, indexCount * sizeof(uint16_t));
+ }
+
+ void updateBones() {
+ // NIMA matrices are a collection of 6 floats.
+ constexpr int kNIMAMatrixSize = 6;
+
+ // Set up the matrices for the first time.
+ if (fBones.size() == 0) {
+ int numMatrices = 1;
+ if (fSkinned) {
+ numMatrices = fActorImage->boneInfluenceMatricesLength() / kNIMAMatrixSize;
+ }
+ fBones.assign(numMatrices, SkMatrix());
+ }
+
+ if (fSkinned) {
+ // Update the matrices.
+ float* matrixData = fActorImage->boneInfluenceMatrices();
+ for (uint32_t i = 1; i < fBones.size(); i ++) {
+ SkMatrix& matrix = fBones[i];
+ float* data = matrixData + i * kNIMAMatrixSize;
+ nima_to_skmatrix(data, matrix);
+ }
+ }
+
+ // Set the zero matrix to be the world transform.
+ nima_to_skmatrix(fActorImage->worldTransform().values(), fBones[0]);
+ }
+
+ void updateVerticesObject(bool applyDeforms) {
+ std::vector<SkPoint>* positions = &fPositions;
+
+ // Apply deforms if requested.
+ uint32_t vertexCount = fPositions.size();
+ std::vector<SkPoint> deformedPositions;
+ if (applyDeforms) {
+ positions = &deformedPositions;
+ deformedPositions.reserve(vertexCount);
+ for (uint32_t i = 0; i < vertexCount; i ++) {
+ Vec2D nimaPoint(fPositions[i].x(), fPositions[i].y());
+ uint32_t* boneIdx = nullptr;
+ float* boneWgt = nullptr;
+ if (fSkinned) {
+ boneIdx = fBoneIdx[i].indices;
+ boneWgt = fBoneWgt[i].weights;
+ }
+ nimaPoint = this->deform(nimaPoint, boneIdx, boneWgt);
+ deformedPositions.push_back(SkPoint::Make(nimaPoint[0], nimaPoint[1]));
+ }
+ }
+
+ // Update the vertices object.
+ fVertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode,
+ vertexCount,
+ positions->data(),
+ fTexs.data(),
+ nullptr,
+ fBoneIdx.data(),
+ fBoneWgt.data(),
+ fIndices.size(),
+ fIndices.data());
+ }
+
+ void drawVerticesObject(SkCanvas* canvas, bool useBones) const {
+ // Determine the blend mode.
+ SkBlendMode blendMode;
+ switch (fActorImage->blendMode()) {
+ case BlendMode::Off: {
+ blendMode = SkBlendMode::kSrc;
+ break;
+ }
+ case BlendMode::Normal: {
+ blendMode = SkBlendMode::kSrcOver;
+ break;
+ }
+ case BlendMode::Additive: {
+ blendMode = SkBlendMode::kPlus;
+ break;
+ }
+ case BlendMode::Multiply: {
+ blendMode = SkBlendMode::kMultiply;
+ break;
+ }
+ case BlendMode::Screen: {
+ blendMode = SkBlendMode::kScreen;
+ break;
+ }
+ }
+
+ // Set the opacity.
+ fPaint->setAlpha(static_cast<U8CPU>(fActorImage->renderOpacity() * 255));
+
+ // Draw the vertices.
+ if (useBones) {
+ canvas->drawVertices(fVertices, fBones.data(), fBones.size(), blendMode, *fPaint);
+ } else {
+ canvas->drawVertices(fVertices, blendMode, *fPaint);
+ }
+
+ // Reset the opacity.
+ fPaint->setAlpha(255);
+ }
+
+ Vec2D deform(const Vec2D& position, uint32_t* boneIdx, float* boneWgt) const {
+ float px = position[0], py = position[1];
+ float px2 = px, py2 = py;
+ float influence[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+
+ // Apply the world transform.
+ Mat2D worldTransform = fActorImage->worldTransform();
+ px2 = worldTransform[0] * px + worldTransform[2] * py + worldTransform[4];
+ py2 = worldTransform[1] * px + worldTransform[3] * py + worldTransform[5];
+
+ // Apply deformations based on bone offsets.
+ if (boneIdx && boneWgt) {
+ float* matrices = fActorImage->boneInfluenceMatrices();
+
+ for (uint32_t i = 0; i < 4; i ++) {
+ uint32_t index = boneIdx[i];
+ float weight = boneWgt[i];
+ for (int j = 0; j < 6; j ++) {
+ influence[j] += matrices[index * 6 + j] * weight;
+ }
+ }
+
+ px = influence[0] * px2 + influence[2] * py2 + influence[4];
+ py = influence[1] * px2 + influence[3] * py2 + influence[5];
+ } else {
+ px = px2;
+ py = py2;
+ }
+
+ // Return the transformed position.
+ return Vec2D(px, py);
+ }
+
+private:
+ ActorImage* fActorImage;
+ SkImage* fTexture;
+ SkPaint* fPaint;
+
+ bool fSkinned;
+ std::vector<SkPoint> fPositions;
+ std::vector<SkPoint> fTexs;
+ std::vector<SkVertices::BoneIndices> fBoneIdx;
+ std::vector<SkVertices::BoneWeights> fBoneWgt;
+ std::vector<uint16_t> fIndices;
+
+ std::vector<SkMatrix> fBones;
+ sk_sp<SkVertices> fVertices;
+
+ RenderMode fRenderMode;
+};
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Represents an Actor, or an animated character, in NIMA.
+class NIMAActor : public Actor {
+public:
+ NIMAActor(const std::string& basePath)
+ : fTexture(nullptr)
+ , fActorImages()
+ , fPaint()
+ , fAnimations() {
+ // Load the NIMA data.
+ std::string nimaPath((basePath + ".nima").c_str());
+ INHERITED::load(nimaPath);
+
+ // Load the image asset.
+ sk_sp<SkData> imageData = SkData::MakeFromFileName((basePath + ".png").c_str());
+ fTexture = SkImage::MakeFromEncoded(imageData);
+
+ // Create the paint.
+ fPaint.setShader(fTexture->makeShader(nullptr));
+ fPaint.setFilterQuality(SkFilterQuality::kLow_SkFilterQuality);
+
+ // Load the image nodes.
+ fActorImages.reserve(m_ImageNodeCount);
+ for (uint32_t i = 0; i < m_ImageNodeCount; i ++) {
+ fActorImages.emplace_back(m_ImageNodes[i], fTexture.get(), &fPaint);
+ }
+
+ // Sort the image nodes.
+ std::sort(fActorImages.begin(), fActorImages.end(), [](auto a, auto b) {
+ return a.drawOrder() < b.drawOrder();
+ });
+
+ // Get the list of animations.
+ fAnimations.reserve(m_AnimationsCount);
+ for (uint32_t i = 0; i < m_AnimationsCount; i ++) {
+ fAnimations.push_back(m_Animations[i].name());
+ }
+ }
+
+ void render(SkCanvas* canvas, RenderMode renderMode) {
+ // Render the image nodes.
+ for (auto& image : fActorImages) {
+ switch (renderMode) {
+ case kBackend_RenderMode: {
+ // Render with Skia backend.
+ image.renderBackend(canvas);
+ break;
+ }
+ case kImmediate_RenderMode: {
+ // Render with immediate backend.
+ image.renderImmediate(canvas);
+ break;
+ }
+ }
+ }
+ }
+
+ const std::vector<std::string>& getAnimations() const {
+ return fAnimations;
+ }
+
+private:
+ sk_sp<SkImage> fTexture;
+ std::vector<NIMAActorImage> fActorImages;
+ SkPaint fPaint;
+ std::vector<std::string> fAnimations;
+
+ typedef Actor INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+NIMASlide::NIMASlide(const SkString& name, const SkString& path)
+ : fBasePath()
+ , fActor(nullptr)
+ , fPlaying(true)
+ , fTime(0.0f)
+ , fRenderMode(kBackend_RenderMode)
+ , fAnimation(nullptr)
+ , fAnimationIndex(0) {
+ fName = name;
+
+ // Get the path components.
+ SkString baseName = SkOSPath::Basename(path.c_str());
+ baseName.resize(baseName.size() - 5);
+ SkString dirName = SkOSPath::Dirname(path.c_str());
+ SkString basePath = SkOSPath::Join(dirName.c_str(), baseName.c_str());
+
+ // Save the base path.
+ fBasePath = std::string(basePath.c_str());
+}
+
+NIMASlide::~NIMASlide() {}
+
+void NIMASlide::draw(SkCanvas* canvas) {
+ canvas->save();
+
+ canvas->translate(500, 500);
+ canvas->scale(1, -1);
+
+ // Render the actor.
+ fActor->render(canvas, fRenderMode);
+
+ canvas->restore();
+
+ // Render the GUI.
+ this->renderGUI();
+}
+
+void NIMASlide::load(SkScalar winWidth, SkScalar winHeight) {
+ this->resetActor();
+}
+
+void NIMASlide::unload() {
+ // Discard resources.
+ fAnimation = nullptr;
+ fActor.reset(nullptr);
+}
+
+bool NIMASlide::animate(const SkAnimTimer& timer) {
+ // Apply the animation.
+ if (fAnimation) {
+ if (fPlaying) {
+ fTime = std::fmod(timer.secs(), fAnimation->max());
+ }
+ fAnimation->time(fTime);
+ fAnimation->apply(1.0f);
+ }
+ return true;
+}
+
+bool NIMASlide::onChar(SkUnichar c) {
+ return false;
+}
+
+bool NIMASlide::onMouse(SkScalar x, SkScalar y, Window::InputState state, uint32_t modifiers) {
+ return false;
+}
+
+void NIMASlide::resetActor() {
+ // Create the actor.
+ fActor = std::make_unique<NIMAActor>(fBasePath);
+
+ // Get the animation.
+ fAnimation = fActor->animationInstance(fActor->getAnimations()[fAnimationIndex]);
+}
+
+void NIMASlide::renderGUI() {
+ ImGui::SetNextWindowSize(ImVec2(300, 220));
+ ImGui::Begin("NIMA");
+
+ // List of animations.
+ auto animations = const_cast<std::vector<std::string>&>(fActor->getAnimations());
+ ImGui::PushItemWidth(-1);
+ if (ImGui::ListBox("Animations",
+ &fAnimationIndex,
+ vector_getter,
+ reinterpret_cast<void*>(&animations),
+ animations.size(),
+ 5)) {
+ resetActor();
+ }
+
+ // Playback control.
+ ImGui::Spacing();
+ if (ImGui::Button("Play")) {
+ fPlaying = true;
+ }
+ ImGui::SameLine();
+ if (ImGui::Button("Pause")) {
+ fPlaying = false;
+ }
+
+ // Time slider.
+ ImGui::PushItemWidth(-1);
+ ImGui::SliderFloat("Time", &fTime, 0.0f, fAnimation->max(), "Time: %.3f");
+
+ // Backend control.
+ int renderMode = fRenderMode;
+ ImGui::Spacing();
+ ImGui::RadioButton("Skia Backend", &renderMode, 0);
+ ImGui::RadioButton("Immediate Backend", &renderMode, 1);
+ if (renderMode == 0) {
+ fRenderMode = kBackend_RenderMode;
+ } else {
+ fRenderMode = kImmediate_RenderMode;
+ }
+
+ ImGui::End();
+}
diff --git a/tools/viewer/NIMASlide.h b/tools/viewer/NIMASlide.h
new file mode 100644
index 0000000000..d19d10119e
--- /dev/null
+++ b/tools/viewer/NIMASlide.h
@@ -0,0 +1,59 @@
+/*
+* Copyright 2018 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#ifndef NIMASlide_DEFINED
+#define NIMASlide_DEFINED
+
+#include "Slide.h"
+
+#include "SkCanvas.h"
+#include "SkVertices.h"
+#include <nima/Actor.hpp>
+#include <nima/ActorImage.hpp>
+#include <nima/Animation/ActorAnimationInstance.hpp>
+#include <nima/Vec2D.hpp>
+
+class NIMAActor;
+class NIMAActorImage;
+
+enum RenderMode {
+ kBackend_RenderMode = 0,
+ kImmediate_RenderMode = 1,
+};
+
+class NIMASlide : public Slide {
+public:
+ NIMASlide(const SkString& name, const SkString& path);
+ ~NIMASlide() override;
+
+ void draw(SkCanvas* canvas) override;
+ void load(SkScalar winWidth, SkScalar winHeight) override;
+ void unload() override;
+ bool animate(const SkAnimTimer& timer) override;
+
+ bool onChar(SkUnichar c) override;
+ bool onMouse(SkScalar x, SkScalar y, sk_app::Window::InputState state,
+ uint32_t modifiers) override;
+
+private:
+ void resetActor();
+
+ void renderGUI();
+
+private:
+ std::string fBasePath;
+ std::unique_ptr<NIMAActor> fActor;
+
+ bool fPlaying;
+ float fTime;
+ RenderMode fRenderMode;
+
+ nima::ActorAnimationInstance* fAnimation;
+ int fAnimationIndex;
+};
+
+#endif
diff --git a/tools/viewer/Viewer.cpp b/tools/viewer/Viewer.cpp
index 81c1851783..27c88191c3 100644
--- a/tools/viewer/Viewer.cpp
+++ b/tools/viewer/Viewer.cpp
@@ -52,6 +52,10 @@
#include "SkottieSlide.h"
#endif
+#if !(defined(SK_BUILD_FOR_WIN) && defined(__clang__))
+ #include "NIMASlide.h"
+#endif
+
using namespace sk_app;
static std::map<GpuPathRenderers, std::string> gPathRendererNames;
@@ -565,6 +569,12 @@ void Viewer::initSlides() {
[](const SkString& name, const SkString& path) -> sk_sp<Slide> {
return sk_make_sp<SvgSlide>(name, path);}
},
+#if !(defined(SK_BUILD_FOR_WIN) && defined(__clang__))
+ { ".nima", "nima-dir", FLAGS_nimas,
+ [](const SkString& name, const SkString& path) -> sk_sp<Slide> {
+ return sk_make_sp<NIMASlide>(name, path);}
+ },
+#endif
};
SkTArray<sk_sp<Slide>, true> dirSlides;