diff --git a/docs/SkCanvas_Reference.bmh b/docs/SkCanvas_Reference.bmh index c310b11b55..8ec893dfab 100644 --- a/docs/SkCanvas_Reference.bmh +++ b/docs/SkCanvas_Reference.bmh @@ -5749,8 +5749,8 @@ void draw(SkCanvas* canvas) { # ------------------------------------------------------------------------------ -#Method void drawVertices(const SkVertices* vertices, const SkMatrix* bones, int boneCount, - SkBlendMode mode, const SkPaint& paint) +#Method void drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[], + int boneCount, SkBlendMode mode, const SkPaint& paint) Draws Vertices vertices, a triangle mesh, using Clip and Matrix. Bone data is used to deform vertices with bone weights. @@ -5759,7 +5759,7 @@ contains Shader, Blend_Mode mode combines Vertices_Colors with Shader. 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. -boneCount must be at most 100, and thus the size of bones should be at most 100. +boneCount must be at most 80, and thus the size of bones should be at most 80. #Param vertices triangle mesh to draw ## #Param bones bone matrix data ## @@ -5767,7 +5767,7 @@ boneCount must be at most 100, and thus the size of bones should be at most 100. #Param mode combines Vertices_Colors with Shader, if both are present ## #Param paint specifies the Shader, used as Vertices texture, may be nullptr ## -#Example +#NoExample void draw(SkCanvas* canvas) { SkPaint paint; SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } }; @@ -5781,10 +5781,10 @@ void draw(SkCanvas* canvas) { { 1.0f, 0.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f, 0.0f } }; - SkMatrix bones[] = { SkMatrix::I(), - SkMatrix::MakeTrans(0, 20), - SkMatrix::MakeTrans(50, 50), - SkMatrix::MakeTrans(20, 0) }; + SkVertices::Bone bones[] = { {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }}, + {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 20.0f }}, + {{ 1.0f, 0.0f, 0.0f, 1.0f, 50.0f, 50.0f }}, + {{ 1.0f, 0.0f, 0.0f, 1.0f, 20.0f, 0.0f }} }; paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 4, SkShader::kClamp_TileMode)); auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode, @@ -5799,8 +5799,8 @@ void draw(SkCanvas* canvas) { # ------------------------------------------------------------------------------ -#Method void drawVertices(const sk_sp& vertices, const SkMatrix* bones, int boneCount, - SkBlendMode mode, const SkPaint& paint) +#Method void drawVertices(const sk_sp& vertices, const SkVertices::Bone bones[], + int boneCount, SkBlendMode mode, const SkPaint& paint) Draws Vertices vertices, a triangle mesh, using Clip and Matrix. Bone data is used to deform vertices with bone weights. @@ -5809,7 +5809,7 @@ contains Shader, Blend_Mode mode combines Vertices_Colors with Shader. 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. -boneCount must be at most 100, and thus the size of bones should be at most 100. +boneCount must be at most 80, and thus the size of bones should be at most 80. #Param vertices triangle mesh to draw ## #Param bones bone matrix data ## @@ -5817,7 +5817,7 @@ boneCount must be at most 100, and thus the size of bones should be at most 100. #Param mode combines Vertices_Colors with Shader, if both are present ## #Param paint specifies the Shader, used as Vertices texture, may be nullptr ## -#Example +#NoExample void draw(SkCanvas* canvas) { SkPaint paint; SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } }; @@ -5831,10 +5831,10 @@ void draw(SkCanvas* canvas) { { 1.0f, 0.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f, 0.0f } }; - SkMatrix bones[] = { SkMatrix::I(), - SkMatrix::MakeTrans(0, 20), - SkMatrix::MakeTrans(50, 50), - SkMatrix::MakeTrans(20, 0) }; + SkVertices::Bone bones[] = { {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }}, + {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 20.0f }}, + {{ 1.0f, 0.0f, 0.0f, 1.0f, 50.0f, 50.0f }}, + {{ 1.0f, 0.0f, 0.0f, 1.0f, 20.0f, 0.0f }} }; paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 4, SkShader::kClamp_TileMode)); auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode, diff --git a/docs/undocumented.bmh b/docs/undocumented.bmh index 6161398a1a..30c06576a4 100644 --- a/docs/undocumented.bmh +++ b/docs/undocumented.bmh @@ -7,7 +7,7 @@ API BMP GIF HEIF ICO JPEG PNG WBMP WebP CPU - GPU GPU-backed OpenGL Vulkan I/O MSAA + GPU GPU-backed OpenGL Vulkan I/O MSAA PDF XPS RFC NaN NaNs @@ -81,8 +81,8 @@ FT_Load_Glyph #Substitute unhinted ## -# this jargon requires a substitute to space the phrase. -#Topic Little_Endian +# this jargon requires a substitute to space the phrase. +#Topic Little_Endian #Substitute little endian ## @@ -90,11 +90,11 @@ FT_Load_Glyph #Substitute big endian ## -#Topic YUV_Component_Y +#Topic YUV_Component_Y #Substitute YUV component y ## -#Topic YUV_Component_U +#Topic YUV_Component_U #Substitute YUV component u ## @@ -106,7 +106,7 @@ FT_Load_Glyph #Substitute UV mapping ## -#Topic Multi_Sample_Anti_Aliasing +#Topic Multi_Sample_Anti_Aliasing #Substitute multi-sample anti-aliasing ## @@ -114,43 +114,43 @@ FT_Load_Glyph #Substitute GPU share group ## -#Topic Bezier_Curve +#Topic Bezier_Curve #Substitute Bezier cruve ## -#Topic Coons_Patch +#Topic Coons_Patch #Substitute Coons patch ## -#Topic Cartesian_Coordinate +#Topic Cartesian_Coordinate #Substitute Cartesian coordinate ## -#Topic Euclidean_Distance +#Topic Euclidean_Distance #Substitute Euclidean distance ## -#Topic Euclidean_Space +#Topic Euclidean_Space #Substitute Euclidean space ## -#Topic HTML_Gray +#Topic HTML_Gray #Substitute HTML gray ## -#Topic HTML_Silver +#Topic HTML_Silver #Substitute HTML silver ## -#Topic HTML_Lime +#Topic HTML_Lime #Substitute HTML lime ## -#Topic HTML_Green +#Topic HTML_Green #Substitute HTML green ## -#Topic HTML_Aqua +#Topic HTML_Aqua #Substitute HTML aqua ## @@ -158,7 +158,7 @@ FT_Load_Glyph #Substitute HTML fuchsia ## -#Topic SVG_lightgray +#Topic SVG_lightgray #Substitute SVG light gray ## @@ -787,6 +787,8 @@ FT_Load_Glyph #Topic Vertices #Class SkVertices +#Class Bone +## ## #Subtopic Colors ## diff --git a/docs/usingBookmaker.bmh b/docs/usingBookmaker.bmh index f74db8f77f..4e952e2b50 100644 --- a/docs/usingBookmaker.bmh +++ b/docs/usingBookmaker.bmh @@ -147,6 +147,7 @@ Complete rebuilding of all bookmaker output looks like: $ ./out/skia/bookmaker -a docs/status.json -e fiddle.json $ ~/go/bin/fiddlecli --input fiddle.json --output fiddleout.json $ ./out/skia/bookmaker -a docs/status.json -f fiddleout.json -r site/user/api -c +$ ./out/skia/bookmaker -a docs/status.json -f fiddleout.json -r site/user/api $ ./out/skia/bookmaker -a docs/status.json -x $ ./out/skia/bookmaker -a docs/status.json -p ## diff --git a/gm/skinning.cpp b/gm/skinning.cpp index 9b59594dc4..44a1b131e4 100644 --- a/gm/skinning.cpp +++ b/gm/skinning.cpp @@ -18,14 +18,14 @@ static const int kCellSize = 60; static const int kColumnSize = 36; static const int kBoneCount = 7; -static const SkMatrix kBones[] = { - SkMatrix::I(), - SkMatrix::MakeTrans(10, 0), - SkMatrix::MakeTrans(0, 10), - SkMatrix::MakeTrans(-10, 0), - SkMatrix::MakeTrans(0, -10), - SkMatrix::MakeScale(0.5f), - SkMatrix::MakeScale(1.5f), +static const SkVertices::Bone kBones[] = { + {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }}, // SkMatrix::I() + {{ 1.0f, 0.0f, 0.0f, 1.0f, 10.0f, 0.0f }}, // SkMatrix::MakeTrans(10, 0) + {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 10.0f }}, // SkMatrix::MakeTrans(0, 10) + {{ 1.0f, 0.0f, 0.0f, 1.0f, -10.0f, 0.0f }}, // SkMatrix::MakeTrans(-10, 0) + {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, -10.0f }}, // SkMatrix::MakeTrans(0, -10) + {{ 0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f }}, // SkMatrix::MakeScale(0.5) + {{ 1.5f, 0.0f, 0.0f, 1.5f, 0.0f, 0.0f }}, // SkMatrix::MakeScale(1.5) }; static const int kVertexCount = 4; @@ -60,9 +60,9 @@ static const uint16_t kIndices[] = { 2, 3, 0, }; -// Swap two SkMatrix pointers in place. -static void swap(const SkMatrix** x, const SkMatrix** y) { - const SkMatrix* temp = *x; +// Swap two SkVertices::Bone pointers in place. +static void swap(const SkVertices::Bone** x, const SkVertices::Bone** y) { + const SkVertices::Bone* temp = *x; *x = *y; *y = temp; } @@ -116,7 +116,7 @@ protected: int ypos = kCellSize; // Create the mutable set of bones. - const SkMatrix* bones[kBoneCount]; + const SkVertices::Bone* bones[kBoneCount]; for (int i = 0; i < kBoneCount; i ++) { bones[i] = &kBones[i]; } @@ -129,14 +129,14 @@ private: void drawPermutations(SkCanvas* canvas, int& xpos, int& ypos, - const SkMatrix** bones, + const SkVertices::Bone** bones, int start) { if (start == kBoneCount) { // Reached the end of the permutations, so draw. canvas->save(); // Copy the bones. - SkMatrix copiedBones[kBoneCount]; + SkVertices::Bone copiedBones[kBoneCount]; for (int i = 0; i < kBoneCount; i ++) { copiedBones[i] = *bones[i]; } @@ -146,42 +146,11 @@ private: // Draw the vertices. if (fDeformUsingCPU) { + // Apply the bones. + sk_sp vertices = fVertices->applyBones(copiedBones, + kBoneCount); + // Deform with CPU. - std::vector positions(kVertexCount); - for (int i = 0; i < kVertexCount; i ++) { - const SkVertices::BoneIndices& indices = kBoneIndices[i]; - const SkVertices::BoneWeights& weights = kBoneWeights[i]; - - // Apply deformations. - SkPoint& result = positions[i]; - SkPoint transformed; - for (uint32_t j = 0; j < 4; j ++) { - // Get the bone attachment data. - uint32_t index = indices.indices[j]; - float weight = weights.weights[j]; - - // Skip the bone is there is no weight. - if (weight == 0.0f) { - continue; - } - SkASSERT(index != 0); - - // transformed = M * v - copiedBones[index].mapPoints(&transformed, &kPositions[i], 1); - - // result += transformed * w - result += transformed * weight; - } - } - - sk_sp vertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, - kVertexCount, - positions.data(), - nullptr, - kColors, - kIndexCount, - kIndices, - !fCache); canvas->drawVertices(vertices.get(), SkBlendMode::kSrc, fPaint); diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h index 594ecb3fee..9a743b10d6 100644 --- a/include/core/SkCanvas.h +++ b/include/core/SkCanvas.h @@ -25,6 +25,7 @@ #include "SkPaint.h" #include "SkRasterHandleAllocator.h" #include "SkSurfaceProps.h" +#include "SkVertices.h" class GrContext; class GrRenderTargetContext; @@ -50,7 +51,6 @@ struct SkRSXform; class SkSurface; class SkSurface_Base; class SkTextBlob; -class SkVertices; /** \class SkCanvas SkCanvas provides an interface for drawing, and how the drawing is clipped and transformed. @@ -2149,7 +2149,7 @@ public: 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. - boneCount must be at most 100, and thus the size of bones should be at most 100. + boneCount must be at most 80, and thus the size of bones should be at most 80. @param vertices triangle mesh to draw @param bones bone matrix data @@ -2157,7 +2157,7 @@ public: @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, + void drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[], int boneCount, SkBlendMode mode, const SkPaint& paint); /** Draws SkVertices vertices, a triangle mesh, using clip and SkMatrix. Bone data is used to @@ -2167,7 +2167,7 @@ public: 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. - boneCount must be at most 100, and thus the size of bones should be at most 100. + boneCount must be at most 80, and thus the size of bones should be at most 80. @param vertices triangle mesh to draw @param bones bone matrix data @@ -2175,8 +2175,8 @@ public: @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& vertices, const SkMatrix* bones, int boneCount, - SkBlendMode mode, const SkPaint& paint); + void drawVertices(const sk_sp& vertices, const SkVertices::Bone 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. @@ -2496,7 +2496,7 @@ protected: const SkPaint& paint) { this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint); } - virtual void onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones, + virtual void onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[], int boneCount, SkBlendMode mode, const SkPaint& paint); virtual void onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint); diff --git a/include/core/SkCanvasVirtualEnforcer.h b/include/core/SkCanvasVirtualEnforcer.h index 84b209d895..7e779a164f 100644 --- a/include/core/SkCanvasVirtualEnforcer.h +++ b/include/core/SkCanvasVirtualEnforcer.h @@ -48,8 +48,8 @@ protected: const SkPaint& paint) override = 0; void onDrawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) override = 0; - void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode, - const SkPaint&) override = 0; + void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, + SkBlendMode, const SkPaint&) override = 0; void onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) override = 0; diff --git a/include/core/SkOverdrawCanvas.h b/include/core/SkOverdrawCanvas.h index 380f9ebb87..aab47d4450 100644 --- a/include/core/SkOverdrawCanvas.h +++ b/include/core/SkOverdrawCanvas.h @@ -39,8 +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*, const SkMatrix* bones, int boneCount, SkBlendMode, - const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, + SkBlendMode, const SkPaint&) override; void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int, SkBlendMode, const SkRect*, const SkPaint*) override; void onDrawPath(const SkPath&, const SkPaint&) override; diff --git a/include/core/SkVertices.h b/include/core/SkVertices.h index 9c1300b0a5..63a27a0ad0 100644 --- a/include/core/SkVertices.h +++ b/include/core/SkVertices.h @@ -24,6 +24,18 @@ public: // to 0. struct BoneIndices { uint32_t indices[4]; + + uint32_t& operator[] (int i) { + SkASSERT(i >= 0); + SkASSERT(i < 4); + return indices[i]; + } + + const uint32_t& operator[] (int i) const { + SkASSERT(i >= 0); + SkASSERT(i < 4); + return indices[i]; + } }; // BoneWeights stores the interpolation weight for each of the (maximum of 4) bones a given @@ -31,6 +43,55 @@ public: // slot should be 0. struct BoneWeights { float weights[4]; + + float& operator[] (int i) { + SkASSERT(i >= 0); + SkASSERT(i < 4); + return weights[i]; + } + + const float& operator[] (int i) const { + SkASSERT(i >= 0); + SkASSERT(i < 4); + return weights[i]; + } + }; + + // Bone stores a 3x2 transformation matrix in column major order: + // | scaleX skewX transX | + // | skewY scaleY transY | + // SkRSXform is insufficient because bones can have non uniform scale. + struct Bone { + float values[6]; + + float& operator[] (int i) { + SkASSERT(i >= 0); + SkASSERT(i < 6); + return values[i]; + } + + const float& operator[] (int i) const { + SkASSERT(i >= 0); + SkASSERT(i < 6); + return values[i]; + } + + SkPoint mapPoint(const SkPoint& point) const { + float x = values[0] * point.x() + values[2] * point.y() + values[4]; + float y = values[1] * point.x() + values[3] * point.y() + values[5]; + return SkPoint::Make(x, y); + } + + SkRect mapRect(const SkRect& rect) const { + SkRect dst = SkRect::MakeEmpty(); + SkPoint quad[4]; + rect.toQuad(quad); + for (int i = 0; i < 4; i ++) { + quad[i] = mapPoint(quad[i]); + } + dst.setBoundsNoCheck(quad, 4); + return dst; + } }; enum VertexMode { @@ -168,6 +229,8 @@ public: bool isVolatile() const { return fIsVolatile; } + sk_sp applyBones(const Bone bones[], int boneCount) const; + // returns approximate byte size of the vertices object size_t approximateSize() const; diff --git a/include/utils/SkLuaCanvas.h b/include/utils/SkLuaCanvas.h index e29e0b5eb3..0b43da6574 100644 --- a/include/utils/SkLuaCanvas.h +++ b/include/utils/SkLuaCanvas.h @@ -58,8 +58,8 @@ protected: const SkPaint*, SrcRectConstraint) override; void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override; - void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode, - const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, + SkBlendMode, const SkPaint&) override; void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; diff --git a/include/utils/SkNWayCanvas.h b/include/utils/SkNWayCanvas.h index f7307d9649..793081ab75 100644 --- a/include/utils/SkNWayCanvas.h +++ b/include/utils/SkNWayCanvas.h @@ -71,8 +71,8 @@ protected: const SkPaint*) override; void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override; - void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode, - const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, + SkBlendMode, const SkPaint&) override; void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int, SkBlendMode, const SkRect*, const SkPaint*) override; void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override; diff --git a/include/utils/SkNoDrawCanvas.h b/include/utils/SkNoDrawCanvas.h index 0e86ed65e7..5043131de8 100644 --- a/include/utils/SkNoDrawCanvas.h +++ b/include/utils/SkNoDrawCanvas.h @@ -75,7 +75,7 @@ protected: const SkPaint*) override {} void onDrawBitmapLattice(const SkBitmap&, const Lattice&, const SkRect&, const SkPaint*) override {} - void onDrawVerticesObject(const SkVertices*, const SkMatrix*, int, SkBlendMode, + void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone[], int, SkBlendMode, const SkPaint&) override {} void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int, SkBlendMode, const SkRect*, const SkPaint*) override {} diff --git a/include/utils/SkPaintFilterCanvas.h b/include/utils/SkPaintFilterCanvas.h index 4728792013..1a5b59db5c 100644 --- a/include/utils/SkPaintFilterCanvas.h +++ b/include/utils/SkPaintFilterCanvas.h @@ -88,8 +88,8 @@ protected: const SkPaint*) override; void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, const SkPaint*) override; - void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode, - const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, + SkBlendMode, const SkPaint&) override; void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4], SkBlendMode, const SkPaint& paint) override; diff --git a/site/user/api/SkCanvas_Reference.md b/site/user/api/SkCanvas_Reference.md index 12ff4197ac..83a24e671f 100644 --- a/site/user/api/SkCanvas_Reference.md +++ b/site/user/api/SkCanvas_Reference.md @@ -3808,11 +3808,11 @@ device bounds empty = true - drawVertices(const SkVertices* vertices, const SkMatrix* bones, int boneCount, SkBlendMode mode, const SkPaint& paint) + drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[], int boneCount, SkBlendMode mode, const SkPaint& paint) - drawVertices(const sk sp<SkVertices>& vertices, const SkMatrix* bones, int boneCount, SkBlendMode mode, const SkPaint& paint) + drawVertices(const sk sp<SkVertices>& vertices, const SkVertices::Bone bones[], int boneCount, SkBlendMode mode, const SkPaint& paint) @@ -6534,8 +6534,8 @@ contains Shader,
-void drawVertices(const SkVertices* vertices, const SkMatrix* bones, int boneCount, SkBlendMode mode,
-                  const SkPaint& paint)
+void drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[], int boneCount,
+                  SkBlendMode mode, const SkPaint& paint)
 
Draws Vertices vertices, a triangle mesh, using Clip and Matrix. Bone data is used to @@ -6545,7 +6545,7 @@ contains Shader, 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. -boneCount must be at most 100, and thus the size of bones should be at most 100. +boneCount must be at most 80, and thus the size of bones should be at most 80. ### Parameters @@ -6566,10 +6566,6 @@ it should be the identity matrix. -### Example - -
- ### See Also drawPatch[2] drawPicture[2][3][4] @@ -6579,7 +6575,7 @@ it should be the identity matrix.
-void drawVertices(const sk sp<SkVertices>& vertices, const SkMatrix* bones, int boneCount,
+void drawVertices(const sk sp<SkVertices>& vertices, const SkVertices::Bone bones[], int boneCount,
                   SkBlendMode mode, const SkPaint& paint)
 
@@ -6590,7 +6586,7 @@ contains Shader, 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. -boneCount must be at most 100, and thus the size of bones should be at most 100. +boneCount must be at most 80, and thus the size of bones should be at most 80. ### Parameters @@ -6611,10 +6607,6 @@ it should be the identity matrix. -### Example - -
- ### See Also drawPatch[2] drawPicture[2][3][4] diff --git a/site/user/api/catalog.htm b/site/user/api/catalog.htm index 7f8fa2868c..5b9aea5be0 100644 --- a/site/user/api/catalog.htm +++ b/site/user/api/catalog.htm @@ -5353,22 +5353,6 @@ "hash": "e8bdae9bea3227758989028424fcac3d", "file": "SkCanvas_Reference", "name": "SkCanvas::drawVertices_2" -}, - "SkCanvas_drawVertices_3": { - "code": "void draw(SkCanvas* canvas) {\n SkPaint paint;\n SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } };\n SkPoint texs[] = { { 0, 0 }, { 0, 250 }, { 250, 250 }, { 250, 0 } };\n SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN };\n SkVertices::BoneIndices boneIndices[] = { { 0, 0, 0, 0 },\n { 1, 0, 0, 0 },\n { 2, 0, 0, 0 },\n { 3, 0, 0, 0 } };\n SkVertices::BoneWeights boneWeights[] = { { 0.0f, 0.0f, 0.0f, 0.0f },\n { 1.0f, 0.0f, 0.0f, 0.0f },\n { 1.0f, 0.0f, 0.0f, 0.0f },\n { 1.0f, 0.0f, 0.0f, 0.0f } };\n SkMatrix bones[] = { SkMatrix::I(),\n SkMatrix::MakeTrans(0, 20),\n SkMatrix::MakeTrans(50, 50),\n SkMatrix::MakeTrans(20, 0) };\n paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 4,\n SkShader::kClamp_TileMode));\n auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode,\n SK_ARRAY_COUNT(points), points, texs, colors, boneIndices, boneWeights);\n canvas->drawVertices(vertices.get(), bones, SK_ARRAY_COUNT(bones), SkBlendMode::kDarken, paint);\n}\n", - "width": 256, - "height": 256, - "hash": "7db6ad6b01931d713d7390736239001b", - "file": "SkCanvas_Reference", - "name": "SkCanvas::drawVertices_3" -}, - "SkCanvas_drawVertices_4": { - "code": "void draw(SkCanvas* canvas) {\n SkPaint paint;\n SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } };\n SkPoint texs[] = { { 0, 0 }, { 0, 250 }, { 250, 250 }, { 250, 0 } };\n SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN };\n SkVertices::BoneIndices boneIndices[] = { { 0, 0, 0, 0 },\n { 1, 0, 0, 0 },\n { 2, 0, 0, 0 },\n { 3, 0, 0, 0 } };\n SkVertices::BoneWeights boneWeights[] = { { 0.0f, 0.0f, 0.0f, 0.0f },\n { 1.0f, 0.0f, 0.0f, 0.0f },\n { 1.0f, 0.0f, 0.0f, 0.0f },\n { 1.0f, 0.0f, 0.0f, 0.0f } };\n SkMatrix bones[] = { SkMatrix::I(),\n SkMatrix::MakeTrans(0, 20),\n SkMatrix::MakeTrans(50, 50),\n SkMatrix::MakeTrans(20, 0) };\n paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 4,\n SkShader::kClamp_TileMode));\n auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode,\n SK_ARRAY_COUNT(points), points, texs, colors, boneIndices, boneWeights);\n canvas->drawVertices(vertices, bones, SK_ARRAY_COUNT(bones), SkBlendMode::kDarken, paint);\n}\n", - "width": 256, - "height": 256, - "hash": "cc1fc7f3462abc79ec6dec3405e2812d", - "file": "SkCanvas_Reference", - "name": "SkCanvas::drawVertices_4" }, "SkCanvas_getGrContext": { "code": "void draw(SkCanvas* canvas) {\n if (canvas->getGrContext()) {\n canvas->clear(SK_ColorRED);\n } else {\n canvas->clear(SK_ColorBLUE);\n }\n}\n", diff --git a/site/user/api/undocumented.md b/site/user/api/undocumented.md index 8c06cb24c2..e4ca275472 100644 --- a/site/user/api/undocumented.md +++ b/site/user/api/undocumented.md @@ -645,6 +645,8 @@ bool isValid() const # Class SkVertices +# Class SkVertices::Bone + ## Colors ## Texs diff --git a/site/user/api/usingBookmaker.md b/site/user/api/usingBookmaker.md index 684e906ed5..e010cd9785 100644 --- a/site/user/api/usingBookmaker.md +++ b/site/user/api/usingBookmaker.md @@ -127,6 +127,7 @@ Complete rebuilding of all bookmaker output looks like: $ ./out/skia/bookmaker -a docs/status.json -e fiddle.json $ ~/go/bin/fiddlecli --input fiddle.json --output fiddleout.json $ ./out/skia/bookmaker -a docs/status.json -f fiddleout.json -r site/user/api -c +$ ./out/skia/bookmaker -a docs/status.json -f fiddleout.json -r site/user/api $ ./out/skia/bookmaker -a docs/status.json -x $ ./out/skia/bookmaker -a docs/status.json -p diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp index 7b11980f8c..52fed029d7 100644 --- a/src/core/SkBitmapDevice.cpp +++ b/src/core/SkBitmapDevice.cpp @@ -593,8 +593,8 @@ void SkBitmapDevice::drawGlyphRunList(const SkGlyphRunList& glyphRunList) { #endif } -void SkBitmapDevice::drawVertices(const SkVertices* vertices, const SkMatrix* bones, int boneCount, - SkBlendMode bmode, const SkPaint& paint) { +void SkBitmapDevice::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[], + int boneCount, SkBlendMode bmode, const SkPaint& paint) { BDDraw(this).drawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(), vertices->texCoords(), vertices->colors(), vertices->boneIndices(), vertices->boneWeights(), bmode, vertices->indices(), diff --git a/src/core/SkBitmapDevice.h b/src/core/SkBitmapDevice.h index a578d2cbea..65971ed60f 100644 --- a/src/core/SkBitmapDevice.h +++ b/src/core/SkBitmapDevice.h @@ -102,7 +102,7 @@ protected: const SkPaint&, SkCanvas::SrcRectConstraint) override; void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override; - void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode, + void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode, const SkPaint& paint) override; void drawDevice(SkBaseDevice*, int x, int y, const SkPaint&) override; diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 1da6e28f1f..fb9e499150 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -1678,16 +1678,16 @@ void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint); } -void SkCanvas::drawVertices(const sk_sp& vertices, const SkMatrix* bones, int boneCount, - SkBlendMode mode, const SkPaint& paint) { +void SkCanvas::drawVertices(const sk_sp& vertices, const SkVertices::Bone bones[], + int boneCount, SkBlendMode mode, const SkPaint& paint) { TRACE_EVENT0("skia", TRACE_FUNC); RETURN_ON_NULL(vertices); SkASSERT(boneCount <= 80); this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint); } -void SkCanvas::drawVertices(const SkVertices* vertices, const SkMatrix* bones, int boneCount, - SkBlendMode mode, const SkPaint& paint) { +void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[], + int boneCount, SkBlendMode mode, const SkPaint& paint) { TRACE_EVENT0("skia", TRACE_FUNC); RETURN_ON_NULL(vertices); SkASSERT(boneCount <= 80); @@ -2576,7 +2576,7 @@ void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, this->onDrawTextBlob(blob, x, y, paint); } -void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones, +void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[], int boneCount, SkBlendMode bmode, const SkPaint& paint) { LOOPER_BEGIN(paint, nullptr) diff --git a/src/core/SkColorSpaceXformCanvas.cpp b/src/core/SkColorSpaceXformCanvas.cpp index 949dd4a2e3..d0032b4c95 100644 --- a/src/core/SkColorSpaceXformCanvas.cpp +++ b/src/core/SkColorSpaceXformCanvas.cpp @@ -90,7 +90,8 @@ public: const SkPaint& paint) override { fTarget->drawPoints(mode, count, pts, fXformer->apply(paint)); } - void onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones, int boneCount, + + void onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[], int boneCount, SkBlendMode mode, const SkPaint& paint) override { sk_sp copy; if (vertices->hasColors()) { diff --git a/src/core/SkDevice.h b/src/core/SkDevice.h index e00ffddc8c..ad07e8163c 100644 --- a/src/core/SkDevice.h +++ b/src/core/SkDevice.h @@ -213,8 +213,8 @@ protected: const SkRect& dst, const SkPaint&); - virtual void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode, - const SkPaint&) = 0; + virtual void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, + SkBlendMode, const SkPaint&) = 0; virtual void drawShadow(const SkPath&, const SkDrawShadowRec&); virtual void drawGlyphRunList(const SkGlyphRunList& glyphRunList); @@ -420,7 +420,7 @@ 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*, const SkMatrix*, int, SkBlendMode, + void drawVertices(const SkVertices*, const SkVertices::Bone[], int, SkBlendMode, const SkPaint&) override {} private: diff --git a/src/core/SkDraw.h b/src/core/SkDraw.h index ca37c098ce..bf023bc093 100644 --- a/src/core/SkDraw.h +++ b/src/core/SkDraw.h @@ -74,7 +74,7 @@ public: const SkColor colors[], const SkVertices::BoneIndices boneIndices[], const SkVertices::BoneWeights boneWeights[], SkBlendMode bmode, const uint16_t indices[], int ptCount, - const SkPaint& paint, const SkMatrix* bones, int boneCount) const; + const SkPaint& paint, const SkVertices::Bone bones[], int boneCount) const; /** * Overwrite the target with the path's coverage (i.e. its mask). diff --git a/src/core/SkDraw_vertices.cpp b/src/core/SkDraw_vertices.cpp index 4d1ccea496..b9320d4e82 100644 --- a/src/core/SkDraw_vertices.cpp +++ b/src/core/SkDraw_vertices.cpp @@ -167,7 +167,8 @@ void SkDraw::drawVertices(SkVertices::VertexMode vmode, int vertexCount, const SkColor colors[], const SkVertices::BoneIndices boneIndices[], const SkVertices::BoneWeights boneWeights[], SkBlendMode bmode, const uint16_t indices[], int indexCount, - const SkPaint& paint, const SkMatrix* bones, int boneCount) const { + const SkPaint& paint, const SkVertices::Bone bones[], + int boneCount) const { SkASSERT(0 == vertexCount || vertices); // abort early if there is nothing to draw @@ -207,11 +208,9 @@ void SkDraw::drawVertices(SkVertices::VertexMode vmode, int vertexCount, } constexpr size_t kDefVertexCount = 16; - constexpr size_t kDefBoneCount = 8; constexpr size_t kOuterSize = sizeof(SkTriColorShader) + sizeof(SkComposeShader) + - (2 * sizeof(SkPoint) + sizeof(SkPM4f)) * kDefVertexCount + - sizeof(SkMatrix) * kDefBoneCount; + (2 * sizeof(SkPoint) + sizeof(SkPM4f)) * kDefVertexCount; SkSTArenaAlloc outerAlloc; // deform vertices using the skeleton if it is passed in @@ -219,28 +218,21 @@ void SkDraw::drawVertices(SkVertices::VertexMode vmode, int vertexCount, // allocate space for the deformed vertices SkPoint* deformed = outerAlloc.makeArray(vertexCount); - // get the bone matrices - SkMatrix* transformedBones = outerAlloc.makeArray(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 the world transform + SkPoint worldPoint = bones[0].mapPoint(vertices[i]); + // apply bone deformations - SkPoint result = SkPoint::Make(0.0f, 0.0f); - SkPoint transformed; + deformed[i] = SkPoint::Make(0.0f, 0.0f); for (uint32_t j = 0; j < 4; j ++) { // get the attachment data - uint32_t index = indices.indices[j]; - float weight = weights.weights[j]; + uint32_t index = indices[j]; + float weight = weights[j]; // skip the bone if there is no weight if (weight == 0.0f) { @@ -248,19 +240,14 @@ void SkDraw::drawVertices(SkVertices::VertexMode vmode, int vertexCount, } SkASSERT(index != 0); - // transformed = M * v - transformedBones[index].mapPoints(&transformed, &vertices[i], 1); - - // result += transformed * w - result += transformed * weight; + // deformed += M * v * w + deformed[i] += bones[index].mapPoint(worldPoint) * weight; } - - // set the deformed point - deformed[i] = result; } } else { // no bones, so only apply world transform - const SkMatrix& worldTransform = bones[0]; + SkMatrix worldTransform = SkMatrix::I(); + worldTransform.setAffine(bones[0].values); worldTransform.mapPoints(deformed, vertices, vertexCount); } diff --git a/src/core/SkLiteDL.cpp b/src/core/SkLiteDL.cpp index ea3ca6d14b..d4e390183c 100644 --- a/src/core/SkLiteDL.cpp +++ b/src/core/SkLiteDL.cpp @@ -455,7 +455,7 @@ namespace { SkBlendMode mode; SkPaint paint; void draw(SkCanvas* c, const SkMatrix&) const { - c->drawVertices(vertices, pod(this), boneCount, mode, paint); + c->drawVertices(vertices, pod(this), boneCount, mode, paint); } }; struct DrawAtlas final : Op { @@ -660,9 +660,9 @@ void SkLiteDL::drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint void* pod = this->push(count*sizeof(SkPoint), mode, count, paint); copy_v(pod, points,count); } -void SkLiteDL::drawVertices(const SkVertices* vertices, const SkMatrix* bones, int boneCount, - SkBlendMode mode, const SkPaint& paint) { - void* pod = this->push(boneCount * sizeof(SkMatrix), +void SkLiteDL::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[], + int boneCount, SkBlendMode mode, const SkPaint& paint) { + void* pod = this->push(boneCount * sizeof(SkVertices::Bone), vertices, boneCount, mode, diff --git a/src/core/SkLiteDL.h b/src/core/SkLiteDL.h index aa32e0229f..ffcdb89389 100644 --- a/src/core/SkLiteDL.h +++ b/src/core/SkLiteDL.h @@ -72,7 +72,7 @@ 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*, const SkMatrix* bones, int boneCount, SkBlendMode, + void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode, const SkPaint&); void drawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int, SkBlendMode, const SkRect*, const SkPaint*); diff --git a/src/core/SkLiteRecorder.cpp b/src/core/SkLiteRecorder.cpp index 971e62c0d3..fedfa99598 100644 --- a/src/core/SkLiteRecorder.cpp +++ b/src/core/SkLiteRecorder.cpp @@ -175,8 +175,9 @@ void SkLiteRecorder::onDrawPoints(SkCanvas::PointMode mode, const SkPaint& paint) { fDL->drawPoints(mode, count, pts, paint); } -void SkLiteRecorder::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones, - int boneCount, SkBlendMode mode, const SkPaint& paint) { +void SkLiteRecorder::onDrawVerticesObject(const SkVertices* vertices, + const SkVertices::Bone bones[], int boneCount, + SkBlendMode mode, const SkPaint& paint) { fDL->drawVertices(vertices, bones, boneCount, mode, paint); } void SkLiteRecorder::onDrawAtlas(const SkImage* atlas, diff --git a/src/core/SkLiteRecorder.h b/src/core/SkLiteRecorder.h index bc37546add..5ae08fa1a6 100644 --- a/src/core/SkLiteRecorder.h +++ b/src/core/SkLiteRecorder.h @@ -73,8 +73,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*, const SkMatrix* bones, int boneCount, SkBlendMode, - const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, + SkBlendMode, const SkPaint&) override; void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int, SkBlendMode, const SkRect*, const SkPaint*) override; void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override; diff --git a/src/core/SkOverdrawCanvas.cpp b/src/core/SkOverdrawCanvas.cpp index 0e20878793..4e6b8c5694 100644 --- a/src/core/SkOverdrawCanvas.cpp +++ b/src/core/SkOverdrawCanvas.cpp @@ -216,9 +216,9 @@ 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, const SkMatrix* bones, - int boneCount, SkBlendMode blendMode, - const SkPaint& paint) { +void SkOverdrawCanvas::onDrawVerticesObject(const SkVertices* vertices, + const SkVertices::Bone bones[], int boneCount, + SkBlendMode blendMode, const SkPaint& paint) { fList[0]->onDrawVerticesObject(vertices, bones, boneCount, diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp index f63abe724c..4ee0eae4a2 100644 --- a/src/core/SkPicturePlayback.cpp +++ b/src/core/SkPicturePlayback.cpp @@ -616,9 +616,9 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, 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; + const SkVertices::Bone* bones = boneCount ? + (const SkVertices::Bone*) reader->skip(boneCount, sizeof(SkVertices::Bone)) : + nullptr; SkBlendMode bmode = reader->read32LE(SkBlendMode::kLastMode); BREAK_ON_READ_ERROR(reader); diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp index ca36e7e491..81e5135859 100644 --- a/src/core/SkPictureRecord.cpp +++ b/src/core/SkPictureRecord.cpp @@ -682,16 +682,17 @@ void SkPictureRecord::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matri this->validate(initialOffset, size); } -void SkPictureRecord::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones, - int boneCount, SkBlendMode mode, const SkPaint& paint) { +void SkPictureRecord::onDrawVerticesObject(const SkVertices* vertices, + const SkVertices::Bone 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 size = 5 * kUInt32Size + boneCount * sizeof(SkVertices::Bone); size_t initialOffset = this->addDraw(DRAW_VERTICES_OBJECT, &size); this->addPaint(paint); this->addVertices(vertices); this->addInt(boneCount); - fWriter.write(bones, boneCount * sizeof(SkMatrix)); + fWriter.write(bones, boneCount * sizeof(SkVertices::Bone)); this->addInt(static_cast(mode)); this->validate(initialOffset, size); diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h index dc9f4d9bdc..dcec581442 100644 --- a/src/core/SkPictureRecord.h +++ b/src/core/SkPictureRecord.h @@ -196,8 +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*, const SkMatrix* bones, int boneCount, SkBlendMode, - const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, + SkBlendMode, const SkPaint&) override; void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp index 1abd5823af..f7c8dd4344 100644 --- a/src/core/SkRecorder.cpp +++ b/src/core/SkRecorder.cpp @@ -317,7 +317,7 @@ void SkRecorder::onDrawPicture(const SkPicture* pic, const SkMatrix* matrix, con } } -void SkRecorder::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones, +void SkRecorder::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[], int boneCount, SkBlendMode bmode, const SkPaint& paint) { this->append(paint, sk_ref_sp(const_cast(vertices)), diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h index 7fed8eaacc..ce1131f769 100644 --- a/src/core/SkRecorder.h +++ b/src/core/SkRecorder.h @@ -121,8 +121,8 @@ public: const SkPaint*) override; void onDrawBitmapLattice(const SkBitmap&, const Lattice& lattice, const SkRect& dst, const SkPaint*) override; - void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode, - const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, + SkBlendMode, const SkPaint&) override; void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int count, SkBlendMode, const SkRect* cull, const SkPaint*) override; void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override; diff --git a/src/core/SkRecords.h b/src/core/SkRecords.h index 4ec2ae68c7..cce68c96aa 100644 --- a/src/core/SkRecords.h +++ b/src/core/SkRecords.h @@ -344,7 +344,7 @@ RECORD(DrawAtlas, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag, RECORD(DrawVertices, kDraw_Tag|kHasPaint_Tag, SkPaint paint; sk_sp vertices; - PODArray bones; + PODArray bones; int boneCount; SkBlendMode bmode); RECORD(DrawShadowRec, kDraw_Tag, diff --git a/src/core/SkVertices.cpp b/src/core/SkVertices.cpp index 97a136c548..a3a3989535 100644 --- a/src/core/SkVertices.cpp +++ b/src/core/SkVertices.cpp @@ -207,6 +207,69 @@ uint16_t* SkVertices::Builder::indices() { return const_cast(fVertices->indices()); } +/** Makes a copy of the SkVertices and applies a set of bones, then returns the deformed + vertices. + + @param bones The bones to apply. + @param boneCount The number of bones. + @return The transformed SkVertices. +*/ +sk_sp SkVertices::applyBones(const SkVertices::Bone bones[], int boneCount) const { + // If there aren't any bones, then nothing changes. + // We don't check if the SkVertices object has bone indices/weights because there is the case + // where the object can have no indices/weights but still have a world transform applied. + if (!bones || !boneCount) { + return sk_ref_sp(this); + } + SkASSERT(boneCount >= 1); + + // Copy the SkVertices. + sk_sp copy = SkVertices::MakeCopy(this->mode(), + this->vertexCount(), + this->positions(), + this->texCoords(), + this->colors(), + nullptr, + nullptr, + this->indexCount(), + this->indices()); + + // Transform the positions. + for (int i = 0; i < this->vertexCount(); i++) { + SkPoint& position = copy->fPositions[i]; + + // Apply the world transform. + position = bones[0].mapPoint(position); + + // Apply the bone deformations. + if (boneCount > 1) { + SkASSERT(this->boneIndices()); + SkASSERT(this->boneWeights()); + + SkPoint result = SkPoint::Make(0.0f, 0.0f); + const SkVertices::BoneIndices& indices = this->boneIndices()[i]; + const SkVertices::BoneWeights& weights = this->boneWeights()[i]; + for (int j = 0; j < 4; j++) { + int index = indices[j]; + float weight = weights[j]; + if (index == 0 || weight == 0.0f) { + continue; + } + SkASSERT(index < boneCount); + + // result += M * v * w. + result += bones[index].mapPoint(position) * weight; + } + position = result; + } + } + + // Recalculate the bounds. + copy->fBounds.set(copy->fPositions, copy->fVertexCnt); + + return copy; +} + /////////////////////////////////////////////////////////////////////////////////////////////////// sk_sp SkVertices::MakeCopy(VertexMode mode, int vertexCount, diff --git a/src/gpu/GrDefaultGeoProcFactory.cpp b/src/gpu/GrDefaultGeoProcFactory.cpp index 027296c7ac..9d61fb31e2 100644 --- a/src/gpu/GrDefaultGeoProcFactory.cpp +++ b/src/gpu/GrDefaultGeoProcFactory.cpp @@ -31,8 +31,9 @@ enum GPFlag { kBonesAttribute_GPFlag = 0x10, }; -static constexpr int kMaxBones = 80; // Due to GPU memory limitations, only up to 80 bone - // matrices are accepted. +static constexpr int kNumVec2sPerBone = 3; // Our bone matrices are 3x2 matrices passed in as + // vec2s in column major order, and thus there are 3 + // vec2s per bone. class DefaultGeoProc : public GrGeometryProcessor { public: @@ -111,21 +112,36 @@ public: } // Setup bone transforms + // NOTE: This code path is currently unused. Benchmarks have found that for all + // reasonable cases of skinned vertices, the overhead involved in copying and uploading + // bone data makes performing the transformations on the CPU faster than doing so on + // the GPU. This is being kept here in case that changes. const char* transformedPositionName = gp.fInPosition.name(); if (gp.hasBones()) { + // Set up the uniform for the bones. const char* vertBonesUniformName; fBonesUniform = uniformHandler->addUniformArray(kVertex_GrShaderFlag, - kFloat3x3_GrSLType, + kFloat2_GrSLType, "Bones", - kMaxBones, + kMaxBones * kNumVec2sPerBone, &vertBonesUniformName); + + // Set up the bone application function. + SkString applyBoneFunctionName; + this->emitApplyBoneFunction(vertBuilder, + vertBonesUniformName, + &applyBoneFunctionName); + + // Apply the world transform to the position first. vertBuilder->codeAppendf( - "float3 originalPosition = %s[0] * float3(%s, 1);" - "float2 transformedPosition = float2(0);" + "float2 worldPosition = %s(0, %s);" + "float2 transformedPosition = float2(0, 0);" "for (int i = 0; i < 4; i++) {", - vertBonesUniformName, + applyBoneFunctionName.c_str(), gp.fInPosition.name()); + // If the GPU supports unsigned integers, then we can read the index. Otherwise, + // we have to estimate it given the float representation. if (args.fShaderCaps->unsignedSupport()) { vertBuilder->codeAppendf( " byte index = %s[i];", @@ -136,12 +152,13 @@ public: gp.fInBoneIndices.name()); } + // Get the weight and apply the transformation. vertBuilder->codeAppendf( " float weight = %s[i];" - " transformedPosition += (%s[index] * originalPosition * weight).xy;" + " transformedPosition += %s(index, worldPosition) * weight;" "}", gp.fInBoneWeights.name(), - vertBonesUniformName); + applyBoneFunctionName.c_str()); transformedPositionName = "transformedPosition"; } @@ -228,10 +245,40 @@ public: fColorSpaceHelper.setData(pdman, dgp.fColorSpaceXform.get()); if (dgp.hasBones()) { - pdman.setMatrix3fv(fBonesUniform, dgp.boneCount(), dgp.bones()); + pdman.set2fv(fBonesUniform, dgp.boneCount() * kNumVec2sPerBone, dgp.bones()); } } + private: + void emitApplyBoneFunction(GrGLSLVertexBuilder* vertBuilder, + const char* vertBonesUniformName, + SkString* funcName) { + // The bone matrices are passed in as 3x2 matrices in column-major order as groups + // of 3 float2s. This code takes those float2s and performs the matrix operation on + // a given matrix and float2. + static const GrShaderVar gApplyBoneArgs[] = { + GrShaderVar("index", kByte_GrSLType), + GrShaderVar("vec", kFloat2_GrSLType), + }; + SkString body; + body.appendf( + " float2 c0 = %s[index * 3];" + " float2 c1 = %s[index * 3 + 1];" + " float2 c2 = %s[index * 3 + 2];" + " float x = c0.x * vec.x + c1.x * vec.y + c2.x;" + " float y = c0.y * vec.x + c1.y * vec.y + c2.y;" + " return float2(x, y);", + vertBonesUniformName, + vertBonesUniformName, + vertBonesUniformName); + vertBuilder->emitFunction(kFloat2_GrSLType, + "applyBone", + SK_ARRAY_COUNT(gApplyBoneArgs), + gApplyBoneArgs, + body.c_str(), + funcName); + } + private: SkMatrix fViewMatrix; GrColor fColor; @@ -336,13 +383,13 @@ private: GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DefaultGeoProc); #if GR_TEST_UTILS -static constexpr int kNumFloatsPerSkMatrix = 9; +static constexpr int kNumFloatsPerBone = 6; static constexpr int kTestBoneCount = 4; -static constexpr float kTestBones[kTestBoneCount * kNumFloatsPerSkMatrix] = { - 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, - 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, - 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, - 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, +static constexpr float kTestBones[kTestBoneCount * kNumFloatsPerBone] = { + 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, }; sk_sp DefaultGeoProc::TestCreate(GrProcessorTestData* d) { diff --git a/src/gpu/GrDefaultGeoProcFactory.h b/src/gpu/GrDefaultGeoProcFactory.h index 3c4bd8ea46..b5aef98aa3 100644 --- a/src/gpu/GrDefaultGeoProcFactory.h +++ b/src/gpu/GrDefaultGeoProcFactory.h @@ -12,6 +12,8 @@ #include "GrGeometryProcessor.h" #include "GrShaderCaps.h" +constexpr int kMaxBones = 80; // Supports up to 80 bones per mesh. + /* * A factory for creating default Geometry Processors which simply multiply position by the uniform * view matrix and wire through color, coverage, UV coords if requested. diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp index 787bf7ceb0..9664109d8c 100644 --- a/src/gpu/GrRenderTargetContext.cpp +++ b/src/gpu/GrRenderTargetContext.cpp @@ -839,7 +839,7 @@ void GrRenderTargetContext::drawVertices(const GrClip& clip, GrPaint&& paint, const SkMatrix& viewMatrix, sk_sp vertices, - const SkMatrix bones[], + const SkVertices::Bone bones[], int boneCount, GrPrimitiveType* overridePrimType) { ASSERT_SINGLE_OWNER diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h index b0756a0bf7..808d442dbc 100644 --- a/src/gpu/GrRenderTargetContext.h +++ b/src/gpu/GrRenderTargetContext.h @@ -215,7 +215,7 @@ public: GrPaint&& paint, const SkMatrix& viewMatrix, sk_sp vertices, - const SkMatrix bones[], + const SkVertices::Bone bones[], int boneCount, GrPrimitiveType* overridePrimType = nullptr); diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 1fe2ae40b0..6c3bd0a321 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -1484,7 +1484,7 @@ static bool init_vertices_paint(GrContext* context, const GrColorSpaceInfo& colo void SkGpuDevice::wireframeVertices(SkVertices::VertexMode vmode, int vertexCount, const SkPoint vertices[], - const SkMatrix bones[], int boneCount, + const SkVertices::Bone bones[], int boneCount, SkBlendMode bmode, const uint16_t indices[], int indexCount, const SkPaint& paint) { @@ -1548,8 +1548,8 @@ void SkGpuDevice::wireframeVertices(SkVertices::VertexMode vmode, int vertexCoun &primitiveType); } -void SkGpuDevice::drawVertices(const SkVertices* vertices, const SkMatrix bones[], int boneCount, - SkBlendMode mode, const SkPaint& paint) { +void SkGpuDevice::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[], + int boneCount, SkBlendMode mode, const SkPaint& paint) { ASSERT_SINGLE_OWNER GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawVertices", fContext.get()); diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h index a3233ad399..555e25e802 100644 --- a/src/gpu/SkGpuDevice.h +++ b/src/gpu/SkGpuDevice.h @@ -87,7 +87,7 @@ public: void drawPosText(const void* text, size_t len, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint&) override; void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override; - void drawVertices(const SkVertices*, const SkMatrix bones[], int boneCount, SkBlendMode, + void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode, const SkPaint&) override; void drawShadow(const SkPath&, const SkDrawShadowRec&) override; void drawAtlas(const SkImage* atlas, const SkRSXform[], const SkRect[], @@ -244,7 +244,7 @@ private: void drawStrokedLine(const SkPoint pts[2], const SkPaint&); void wireframeVertices(SkVertices::VertexMode, int vertexCount, const SkPoint verts[], - const SkMatrix bones[], int boneCount, SkBlendMode, + const SkVertices::Bone bones[], int boneCount, SkBlendMode, const uint16_t indices[], int indexCount, const SkPaint&); static sk_sp MakeRenderTargetContext(GrContext*, diff --git a/src/gpu/ops/GrDrawVerticesOp.cpp b/src/gpu/ops/GrDrawVerticesOp.cpp index dd91452f5d..04b537f82b 100644 --- a/src/gpu/ops/GrDrawVerticesOp.cpp +++ b/src/gpu/ops/GrDrawVerticesOp.cpp @@ -12,12 +12,10 @@ #include "SkGr.h" #include "SkRectPriv.h" -static constexpr int kNumFloatsPerSkMatrix = 9; - std::unique_ptr GrDrawVerticesOp::Make(GrContext* context, GrPaint&& paint, sk_sp vertices, - const SkMatrix bones[], + const SkVertices::Bone bones[], int boneCount, const SkMatrix& viewMatrix, GrAAType aaType, @@ -32,7 +30,7 @@ std::unique_ptr GrDrawVerticesOp::Make(GrContext* context, } GrDrawVerticesOp::GrDrawVerticesOp(const Helper::MakeArgs& helperArgs, GrColor color, - sk_sp vertices, const SkMatrix bones[], + sk_sp vertices, const SkVertices::Bone bones[], int boneCount, GrPrimitiveType primitiveType, GrAAType aaType, sk_sp colorSpaceXform, const SkMatrix& viewMatrix) @@ -51,26 +49,23 @@ GrDrawVerticesOp::GrDrawVerticesOp(const Helper::MakeArgs& helperArgs, GrColor c mesh.fColor = color; mesh.fViewMatrix = viewMatrix; mesh.fVertices = std::move(vertices); - if (bones) { - // Copy the bone data over in the format that the GPU would upload. - mesh.fBones.reserve(boneCount * kNumFloatsPerSkMatrix); - for (int i = 0; i < boneCount; i ++) { - const SkMatrix& matrix = bones[i]; - mesh.fBones.push_back(matrix.get(SkMatrix::kMScaleX)); - mesh.fBones.push_back(matrix.get(SkMatrix::kMSkewY)); - mesh.fBones.push_back(matrix.get(SkMatrix::kMPersp0)); - mesh.fBones.push_back(matrix.get(SkMatrix::kMSkewX)); - mesh.fBones.push_back(matrix.get(SkMatrix::kMScaleY)); - mesh.fBones.push_back(matrix.get(SkMatrix::kMPersp1)); - mesh.fBones.push_back(matrix.get(SkMatrix::kMTransX)); - mesh.fBones.push_back(matrix.get(SkMatrix::kMTransY)); - mesh.fBones.push_back(matrix.get(SkMatrix::kMPersp2)); - } - } mesh.fIgnoreTexCoords = false; mesh.fIgnoreColors = false; mesh.fIgnoreBones = false; + if (mesh.fVertices->hasBones() && bones) { + // Perform the transformations on the CPU instead of the GPU. + mesh.fVertices = mesh.fVertices->applyBones(bones, boneCount); + } else { + if (bones && boneCount > 1) { + // NOTE: This should never be used. All bone transforms are being done on the CPU + // instead of the GPU. + + // Copy the bone data. + fBones.assign(bones, bones + boneCount); + } + } + fFlags = 0; if (mesh.hasPerVertexColors()) { fFlags |= kRequiresPerVertexColors_Flag; @@ -85,7 +80,9 @@ GrDrawVerticesOp::GrDrawVerticesOp(const Helper::MakeArgs& helperArgs, GrColor c // Special case for meshes with a world transform but no bone weights. // These will be considered normal vertices draws without bones. if (!mesh.fVertices->hasBones() && boneCount == 1) { - mesh.fViewMatrix.preConcat(bones[0]); + SkMatrix worldTransform; + worldTransform.setAffine(bones[0].values); + mesh.fViewMatrix.preConcat(worldTransform); } IsZeroArea zeroArea; @@ -101,7 +98,7 @@ GrDrawVerticesOp::GrDrawVerticesOp(const Helper::MakeArgs& helperArgs, GrColor c SkRect bounds = SkRect::MakeEmpty(); const SkRect originalBounds = bones[0].mapRect(mesh.fVertices->bounds()); for (int i = 1; i < boneCount; i++) { - const SkMatrix& matrix = bones[i]; + const SkVertices::Bone& matrix = bones[i]; bounds.join(matrix.mapRect(originalBounds)); } @@ -188,7 +185,9 @@ sk_sp GrDrawVerticesOp::makeGP(const GrShaderCaps* shaderCa const SkMatrix& vm = this->hasMultipleViewMatrices() ? SkMatrix::I() : fMeshes[0].fViewMatrix; - Bones bones(fMeshes[0].fBones.data(), fMeshes[0].fBones.size() / kNumFloatsPerSkMatrix); + // The bones are packed as 6 floats in column major order, so we can directly upload them to + // the GPU as groups of 3 vec2s. + Bones bones(reinterpret_cast(fBones.data()), fBones.size()); *hasBoneAttribute = this->hasBones(); if (this->hasBones()) { diff --git a/src/gpu/ops/GrDrawVerticesOp.h b/src/gpu/ops/GrDrawVerticesOp.h index 07227e0b43..fd40e461e5 100644 --- a/src/gpu/ops/GrDrawVerticesOp.h +++ b/src/gpu/ops/GrDrawVerticesOp.h @@ -38,16 +38,16 @@ public: static std::unique_ptr Make(GrContext* context, GrPaint&&, sk_sp, - const SkMatrix bones[], + const SkVertices::Bone bones[], int boneCount, const SkMatrix& viewMatrix, GrAAType, sk_sp, GrPrimitiveType* overridePrimType = nullptr); - GrDrawVerticesOp(const Helper::MakeArgs&, GrColor, sk_sp, const SkMatrix bones[], - int boneCount, GrPrimitiveType, GrAAType, sk_sp, - const SkMatrix& viewMatrix); + GrDrawVerticesOp(const Helper::MakeArgs&, GrColor, sk_sp, + const SkVertices::Bone bones[], int boneCount, GrPrimitiveType, GrAAType, + sk_sp, const SkMatrix& viewMatrix); const char* name() const override { return "DrawVerticesOp"; } @@ -103,7 +103,6 @@ private: struct Mesh { GrColor fColor; // Used if this->hasPerVertexColors() is false. sk_sp fVertices; - std::vector fBones; // Transformation matrices stored in GPU format. SkMatrix fViewMatrix; bool fIgnoreTexCoords; bool fIgnoreColors; @@ -118,7 +117,7 @@ private: } bool hasBones() const { - return fVertices->hasBones() && fBones.size() && !fIgnoreBones; + return fVertices->hasBones() && !fIgnoreBones; } }; @@ -152,6 +151,7 @@ private: Helper fHelper; SkSTArray<1, Mesh, true> fMeshes; + std::vector fBones; // Bone transformation matrices. // GrPrimitiveType is more expressive than fVertices.mode() so it is used instead and we ignore // the SkVertices mode (though fPrimitiveType may have been inferred from it). GrPrimitiveType fPrimitiveType; diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index 8664e50182..fb208f8689 100644 --- a/src/pdf/SkPDFDevice.cpp +++ b/src/pdf/SkPDFDevice.cpp @@ -1375,7 +1375,7 @@ void SkPDFDevice::drawGlyphRunList(const SkGlyphRunList& glyphRunList) { } } -void SkPDFDevice::drawVertices(const SkVertices*, const SkMatrix*, int, SkBlendMode, +void SkPDFDevice::drawVertices(const SkVertices*, const SkVertices::Bone[], int, SkBlendMode, const SkPaint&) { if (this->hasEmptyClip()) { return; diff --git a/src/pdf/SkPDFDevice.h b/src/pdf/SkPDFDevice.h index 9a917904b6..0197b5a6d3 100644 --- a/src/pdf/SkPDFDevice.h +++ b/src/pdf/SkPDFDevice.h @@ -97,7 +97,7 @@ public: const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint&) override { SkASSERT(false); } void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override; - void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode, + void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode, const SkPaint&) override; void drawDevice(SkBaseDevice*, int x, int y, const SkPaint&) override; diff --git a/src/pipe/SkPipeCanvas.cpp b/src/pipe/SkPipeCanvas.cpp index 258160c4fe..bf06579709 100644 --- a/src/pipe/SkPipeCanvas.cpp +++ b/src/pipe/SkPipeCanvas.cpp @@ -728,7 +728,7 @@ void SkPipeCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) { write_paint(writer, paint, kGeometry_PaintUsage); } -void SkPipeCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones, +void SkPipeCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[], int boneCount, SkBlendMode bmode, const SkPaint& paint) { unsigned extra = static_cast(bmode); @@ -737,7 +737,7 @@ void SkPipeCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkMatr // TODO: dedup vertices? writer.writeDataAsByteArray(vertices->encode().get()); writer.write32(boneCount); - writer.write(bones, sizeof(SkMatrix) * boneCount); + writer.write(bones, sizeof(SkVertices::Bone) * boneCount); write_paint(writer, paint, kVertices_PaintUsage); } diff --git a/src/pipe/SkPipeCanvas.h b/src/pipe/SkPipeCanvas.h index b39f80920b..a679491419 100644 --- a/src/pipe/SkPipeCanvas.h +++ b/src/pipe/SkPipeCanvas.h @@ -135,8 +135,8 @@ protected: const SkPaint*) override; void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst, const SkPaint*) override; - void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode, - const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, + SkBlendMode, const SkPaint&) override; void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; diff --git a/src/pipe/SkPipeReader.cpp b/src/pipe/SkPipeReader.cpp index 909276f41b..1d77779764 100644 --- a/src/pipe/SkPipeReader.cpp +++ b/src/pipe/SkPipeReader.cpp @@ -567,7 +567,7 @@ static void drawVertices_handler(SkPipeReader& reader, uint32_t packedVerb, SkCa vertices = SkVertices::Decode(data->data(), data->size()); } int boneCount = reader.read32(); - const SkMatrix* bones = boneCount ? reader.skipT(boneCount) : nullptr; + const SkVertices::Bone* bones = boneCount ? reader.skipT(boneCount) : nullptr; if (vertices) { canvas->drawVertices(vertices, bones, boneCount, bmode, read_paint(reader)); } diff --git a/src/svg/SkSVGDevice.cpp b/src/svg/SkSVGDevice.cpp index 1f7ec36b19..593fe40738 100644 --- a/src/svg/SkSVGDevice.cpp +++ b/src/svg/SkSVGDevice.cpp @@ -1040,7 +1040,7 @@ void SkSVGDevice::drawTextOnPath(const void* text, size_t len, const SkPath& pat } } -void SkSVGDevice::drawVertices(const SkVertices*, const SkMatrix*, int, SkBlendMode, +void SkSVGDevice::drawVertices(const SkVertices*, const SkVertices::Bone[], int, SkBlendMode, const SkPaint&) { // todo } diff --git a/src/svg/SkSVGDevice.h b/src/svg/SkSVGDevice.h index 452229db6a..e57ef36819 100644 --- a/src/svg/SkSVGDevice.h +++ b/src/svg/SkSVGDevice.h @@ -42,7 +42,7 @@ protected: void drawTextOnPath(const void* text, size_t len, const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) override; - void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode, + void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode, const SkPaint& paint) override; void drawDevice(SkBaseDevice*, int x, int y, diff --git a/src/utils/SkLuaCanvas.cpp b/src/utils/SkLuaCanvas.cpp index 441857f664..edef7e3a39 100644 --- a/src/utils/SkLuaCanvas.cpp +++ b/src/utils/SkLuaCanvas.cpp @@ -314,8 +314,8 @@ void SkLuaCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) { this->INHERITED::onDrawDrawable(drawable, matrix); } -void SkLuaCanvas::onDrawVerticesObject(const SkVertices*, const SkMatrix*, int, SkBlendMode, - const SkPaint& paint) { +void SkLuaCanvas::onDrawVerticesObject(const SkVertices*, const SkVertices::Bone[], int, + SkBlendMode, const SkPaint& paint) { AUTO_LUA("drawVertices"); lua.pushPaint(paint, "paint"); } diff --git a/src/utils/SkNWayCanvas.cpp b/src/utils/SkNWayCanvas.cpp index 7d1e98106b..ac3a9710c6 100644 --- a/src/utils/SkNWayCanvas.cpp +++ b/src/utils/SkNWayCanvas.cpp @@ -320,7 +320,7 @@ void SkNWayCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) } } -void SkNWayCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones, +void SkNWayCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[], int boneCount, SkBlendMode bmode, const SkPaint& paint) { Iter iter(fList); while (iter.next()) { diff --git a/src/utils/SkPaintFilterCanvas.cpp b/src/utils/SkPaintFilterCanvas.cpp index 929488caea..862bca7dad 100644 --- a/src/utils/SkPaintFilterCanvas.cpp +++ b/src/utils/SkPaintFilterCanvas.cpp @@ -173,9 +173,9 @@ void SkPaintFilterCanvas::onDrawImageLattice(const SkImage* image, const Lattice } } -void SkPaintFilterCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones, - int boneCount, SkBlendMode bmode, - const SkPaint& paint) { +void SkPaintFilterCanvas::onDrawVerticesObject(const SkVertices* vertices, + const SkVertices::Bone bones[], int boneCount, + SkBlendMode bmode, const SkPaint& paint) { AutoPaintFilter apf(this, kVertices_Type, paint); if (apf.shouldDraw()) { this->SkNWayCanvas::onDrawVerticesObject(vertices, bones, boneCount, bmode, *apf.paint()); diff --git a/src/xps/SkXPSDevice.cpp b/src/xps/SkXPSDevice.cpp index ff66e3b66e..e73b726464 100644 --- a/src/xps/SkXPSDevice.cpp +++ b/src/xps/SkXPSDevice.cpp @@ -1156,7 +1156,7 @@ void SkXPSDevice::drawPoints(SkCanvas::PointMode mode, draw(this, &SkDraw::drawPoints, mode, count, points, paint, this); } -void SkXPSDevice::drawVertices(const SkVertices* v, const SkMatrix* bones, int boneCount, +void SkXPSDevice::drawVertices(const SkVertices* v, const SkVertices::Bone bones[], int boneCount, SkBlendMode blendMode, const SkPaint& paint) { draw(this, &SkDraw::drawVertices, v->mode(), v->vertexCount(), v->positions(), v->texCoords(), v->colors(), v->boneIndices(), v->boneWeights(), blendMode, v->indices(), v->indexCount(), diff --git a/src/xps/SkXPSDevice.h b/src/xps/SkXPSDevice.h index c3f27c4261..877eb3b718 100644 --- a/src/xps/SkXPSDevice.h +++ b/src/xps/SkXPSDevice.h @@ -99,7 +99,7 @@ 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*, const SkMatrix* bones, int boneCount, SkBlendMode, + void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode, const SkPaint&) override; void drawDevice(SkBaseDevice*, int x, int y, const SkPaint&) override; diff --git a/tools/debugger/SkDebugCanvas.cpp b/tools/debugger/SkDebugCanvas.cpp index 19b88e9d79..94b6ea96dd 100644 --- a/tools/debugger/SkDebugCanvas.cpp +++ b/tools/debugger/SkDebugCanvas.cpp @@ -445,7 +445,7 @@ 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, const SkMatrix* bones, +void SkDebugCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[], int boneCount, SkBlendMode bmode, const SkPaint& paint) { // TODO: ANIMATION NOT LOGGED this->addDrawCommand(new SkDrawVerticesCommand(sk_ref_sp(const_cast(vertices)), diff --git a/tools/debugger/SkDebugCanvas.h b/tools/debugger/SkDebugCanvas.h index b95614931b..e5747221df 100644 --- a/tools/debugger/SkDebugCanvas.h +++ b/tools/debugger/SkDebugCanvas.h @@ -146,8 +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*, const SkMatrix* bones, int boneCount, SkBlendMode, - const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, + SkBlendMode, const SkPaint&) override; void onDrawPath(const SkPath&, const SkPaint&) override; void onDrawRegion(const SkRegion&, const SkPaint&) override; void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override; diff --git a/tools/viewer/NIMASlide.cpp b/tools/viewer/NIMASlide.cpp index e8827cc686..4d094c4aac 100644 --- a/tools/viewer/NIMASlide.cpp +++ b/tools/viewer/NIMASlide.cpp @@ -18,20 +18,6 @@ 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. @@ -58,11 +44,8 @@ public: , fVertices(nullptr) , fRenderFlags(0) { // Update the vertices and bones. - this->updateVertices(); + this->updateVertices(true); this->updateBones(); - - // Update the vertices object. - this->updateVerticesObject(false, false); } void render(SkCanvas* canvas, uint32_t renderFlags) { @@ -73,47 +56,39 @@ public: bool useCache = renderFlags & kCache_RenderFlag; bool drawBounds = renderFlags & kBounds_RenderFlag; + // Don't use the cache if drawing in immediate mode. + useCache &= !useImmediate; + + if (fActorImage->doesAnimationVertexDeform() || dirty) { + // These are vertices that transform beyond just bone transforms, so they must be + // updated every frame. + // If the render flags are dirty, reset the vertices object. + this->updateVertices(!useCache); + } + + // Update the bones. + this->updateBones(); + + // Deform the bones in immediate mode. + sk_sp vertices = fVertices; if (useImmediate) { - // Immediate mode transforms. - // Update the vertex data. - if (fActorImage->doesAnimationVertexDeform() && fActorImage->isVertexDeformDirty()) { - this->updateVertices(); - fActorImage->isVertexDeformDirty(false); - } - - // Update the vertices object. - this->updateVerticesObject(true, true); // Immediate mode vertices change every frame, - // so they must be volatile. - } else { - // Backend transformations. - if (fActorImage->doesAnimationVertexDeform()) { - // These are vertices that transform beyond just bone transforms, so they must be - // updated every frame. - this->updateVertices(); - this->updateVerticesObject(false, true); - } else if (dirty) { - // If the render flags are dirty, reset the vertices object. - this->updateVertices(); - this->updateVerticesObject(false, !useCache); - } - - // Update the bones. - this->updateBones(); + vertices = fVertices->applyBones(fBones.data(), fBones.size()); } // Draw the vertices object. - this->drawVerticesObject(canvas, !useImmediate); + this->drawVerticesObject(vertices.get(), canvas, !useImmediate); + // Draw the bounds. if (drawBounds && fActorImage->renderOpacity() > 0.0f) { // Get the bounds. - SkRect bounds = fVertices->bounds(); + SkRect bounds = vertices->bounds(); // Approximate bounds if not using immediate transforms. if (!useImmediate) { - const SkRect originalBounds = fBones[0].mapRect(fVertices->bounds()); + const SkRect originalBounds = fBones[0].mapRect(vertices->bounds()); bounds = originalBounds; for (size_t i = 1; i < fBones.size(); i++) { - const SkMatrix& matrix = fBones[i]; + const SkVertices::Bone& matrix = fBones[i]; bounds.join(matrix.mapRect(originalBounds)); } } @@ -129,7 +104,7 @@ public: int drawOrder() const { return fActorImage->drawOrder(); } private: - void updateVertices() { + void updateVertices(bool isVolatile) { // Update whether the image is skinned. fSkinned = fActorImage->connectedBoneCount() > 0; @@ -177,12 +152,24 @@ private: 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(attrBoneIdx[k]); - fBoneWgt[i].weights[k] = attrBoneWgt[k]; + fBoneIdx[i][k] = static_cast(attrBoneIdx[k]); + fBoneWgt[i][k] = attrBoneWgt[k]; } } } memcpy(fIndices.data(), indexData, indexCount * sizeof(uint16_t)); + + // Update the vertices object. + fVertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, + vertexCount, + fPositions.data(), + fTexs.data(), + nullptr, + fBoneIdx.data(), + fBoneWgt.data(), + fIndices.size(), + fIndices.data(), + isVolatile); } void updateBones() { @@ -195,59 +182,24 @@ private: if (fSkinned) { numMatrices = fActorImage->boneInfluenceMatricesLength() / kNIMAMatrixSize; } - fBones.assign(numMatrices, SkMatrix()); + + // Initialize all matrices to the identity matrix. + fBones.assign(numMatrices, {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }}); } 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); - } + memcpy(fBones.data(), matrixData, fBones.size() * kNIMAMatrixSize * sizeof(float)); } // Set the zero matrix to be the world transform. - nima_to_skmatrix(fActorImage->worldTransform().values(), fBones[0]); + memcpy(fBones.data(), + fActorImage->worldTransform().values(), + kNIMAMatrixSize * sizeof(float)); } - void updateVerticesObject(bool applyDeforms, bool isVolatile) { - std::vector* positions = &fPositions; - - // Apply deforms if requested. - uint32_t vertexCount = fPositions.size(); - std::vector 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(), - isVolatile); - } - - void drawVerticesObject(SkCanvas* canvas, bool useBones) const { + void drawVerticesObject(SkVertices* vertices, SkCanvas* canvas, bool useBones) const { // Determine the blend mode. SkBlendMode blendMode; switch (fActorImage->blendMode()) { @@ -278,48 +230,15 @@ private: // Draw the vertices. if (useBones) { - canvas->drawVertices(fVertices, fBones.data(), fBones.size(), blendMode, *fPaint); + canvas->drawVertices(vertices, fBones.data(), fBones.size(), blendMode, *fPaint); } else { - canvas->drawVertices(fVertices, blendMode, *fPaint); + canvas->drawVertices(vertices, 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; @@ -332,8 +251,8 @@ private: std::vector fBoneWgt; std::vector fIndices; - std::vector fBones; - sk_sp fVertices; + std::vector fBones; + sk_sp fVertices; uint32_t fRenderFlags; };