skeletal animation support added to API and software backend
SkCanvas::drawVertices now supports overloads that take an array of bone deformation matrices. SkVertices::MakeCopy and SkVertices::Builder now support two additional optional attributes, boneIndices and boneWeights. Bug: skia: Change-Id: I30a3b11691e7cdb13924907cc1401ff86d127aea Reviewed-on: https://skia-review.googlesource.com/137221 Reviewed-by: Brian Osman <brianosman@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com> Commit-Queue: Ruiqi Mao <ruiqimao@google.com>
This commit is contained in:
parent
38f118a2e7
commit
f510149da8
19
BUILD.gn
19
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) {
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 {}
|
||||
|
@ -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;
|
||||
|
Binary file not shown.
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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;
|
||||
|
@ -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).
|
||||
|
@ -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;
|
||||
|
||||
SkPoint* devVerts = outerAlloc.makeArray<SkPoint>(count);
|
||||
fMatrix->mapPoints(devVerts, vertices, count);
|
||||
// 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>(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),
|
||||
|
@ -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,
|
||||
|
@ -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&);
|
||||
|
@ -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[],
|
||||
|
@ -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;
|
||||
|
@ -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[],
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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],
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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.");
|
||||
|
@ -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);
|
||||
|
516
tools/viewer/NIMASlide.cpp
Normal file
516
tools/viewer/NIMASlide.cpp
Normal file
@ -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();
|
||||
}
|
59
tools/viewer/NIMASlide.h
Normal file
59
tools/viewer/NIMASlide.h
Normal file
@ -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
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user