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:
Ruiqi Mao 2018-06-29 14:32:21 -04:00 committed by Skia Commit-Bot
parent 38f118a2e7
commit f510149da8
55 changed files with 1013 additions and 124 deletions

View File

@ -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) {

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 {}

View File

@ -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.

View File

@ -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) {

View File

@ -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;
///////////////////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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,

View File

@ -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);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -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;

View File

@ -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).

View File

@ -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),

View File

@ -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,

View File

@ -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&);

View File

@ -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[],

View File

@ -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;

View File

@ -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[],

View File

@ -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:

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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],

View File

@ -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;

View File

@ -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;

View File

@ -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);
});
}

View File

@ -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;

View File

@ -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) {

View File

@ -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());

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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));
}
}

View File

@ -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
}

View File

@ -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;

View File

@ -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");
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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) {

View File

@ -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;

View File

@ -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));
}

View File

@ -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;

View File

@ -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.");

View File

@ -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
View 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
View 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

View File

@ -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;