added optimizations to speed up skinning

Docs-Preview: https://skia.org/?cl=145148
Bug: skia:
Change-Id: If27722105a1e8999f6440b6fd4044cc1f327827e
Reviewed-on: https://skia-review.googlesource.com/145148
Commit-Queue: Ruiqi Mao <ruiqimao@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Ruiqi Mao 2018-08-15 10:44:19 -04:00 committed by Skia Commit-Bot
parent 137ca523a3
commit c97a339cd6
58 changed files with 431 additions and 397 deletions

View File

@ -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<SkVertices>& vertices, const SkMatrix* bones, int boneCount,
SkBlendMode mode, const SkPaint& paint)
#Method void drawVertices(const sk_sp<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.
@ -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,

View File

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

View File

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

View File

@ -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<SkVertices> vertices = fVertices->applyBones(copiedBones,
kBoneCount);
// Deform with CPU.
std::vector<SkPoint> 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<SkVertices> vertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode,
kVertexCount,
positions.data(),
nullptr,
kColors,
kIndexCount,
kIndices,
!fCache);
canvas->drawVertices(vertices.get(),
SkBlendMode::kSrc,
fPaint);

View File

@ -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<SkVertices>& vertices, const SkMatrix* bones, int boneCount,
SkBlendMode mode, const SkPaint& paint);
void drawVertices(const sk_sp<SkVertices>& 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);

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*, 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;

View File

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

View File

@ -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<SkVertices> applyBones(const Bone bones[], int boneCount) const;
// returns approximate byte size of the vertices object
size_t approximateSize() const;

View File

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

View File

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

View File

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

View File

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

View File

@ -3808,11 +3808,11 @@ device bounds empty = true
</tr>
<tr style='background-color: #f0f0f0; '>
<td style='text-align: left; border: 2px solid #dddddd; padding: 8px; '></td>
<td style='text-align: left; border: 2px solid #dddddd; padding: 8px; '><a href='#SkCanvas_drawVertices_3'>drawVertices(const SkVertices* vertices, const SkMatrix* bones, int boneCount, SkBlendMode mode, const SkPaint& paint)</a></td>
<td style='text-align: left; border: 2px solid #dddddd; padding: 8px; '><a href='#SkCanvas_drawVertices_3'>drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[], int boneCount, SkBlendMode mode, const SkPaint& paint)</a></td>
</tr>
<tr>
<td style='text-align: left; border: 2px solid #dddddd; padding: 8px; '></td>
<td style='text-align: left; border: 2px solid #dddddd; padding: 8px; '><a href='#SkCanvas_drawVertices_4'>drawVertices(const sk sp&lt;SkVertices&gt;& vertices, const SkMatrix* bones, int boneCount, SkBlendMode mode, const SkPaint& paint)</a></td>
<td style='text-align: left; border: 2px solid #dddddd; padding: 8px; '><a href='#SkCanvas_drawVertices_4'>drawVertices(const sk sp&lt;SkVertices&gt;& vertices, const SkVertices::Bone bones[], int boneCount, SkBlendMode mode, const SkPaint& paint)</a></td>
</tr>
</table>
@ -6534,8 +6534,8 @@ contains <a href='undocumented#Shader'>Shader</a>, <a href='SkBlendMode_Referenc
<a name='SkCanvas_drawVertices_3'></a>
<pre style="padding: 1em 1em 1em 1em; width: 62.5em;background-color: #f0f0f0">
void <a href='#SkCanvas_drawVertices'>drawVertices</a>(const <a href='undocumented#SkVertices'>SkVertices</a>* vertices, const <a href='SkMatrix_Reference#SkMatrix'>SkMatrix</a>* bones, int boneCount, <a href='SkBlendMode_Reference#SkBlendMode'>SkBlendMode</a> mode,
const <a href='SkPaint_Reference#SkPaint'>SkPaint</a>& paint)
void <a href='#SkCanvas_drawVertices'>drawVertices</a>(const <a href='undocumented#SkVertices'>SkVertices</a>* vertices, const <a href='undocumented#SkVertices_Bone'>SkVertices::Bone</a> bones[], int boneCount,
<a href='SkBlendMode_Reference#SkBlendMode'>SkBlendMode</a> mode, const <a href='SkPaint_Reference#SkPaint'>SkPaint</a>& paint)
</pre>
Draws <a href='undocumented#Vertices'>Vertices</a> <a href='#SkCanvas_drawVertices_3_vertices'>vertices</a>, a triangle mesh, using <a href='#Clip'>Clip</a> and <a href='#Matrix'>Matrix</a>. Bone data is used to
@ -6545,7 +6545,7 @@ contains <a href='undocumented#Shader'>Shader</a>, <a href='SkBlendMode_Referenc
The first element of <a href='#SkCanvas_drawVertices_3_bones'>bones</a> 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.
<a href='#SkCanvas_drawVertices_3_boneCount'>boneCount</a> must be at most 100, and thus the size of <a href='#SkCanvas_drawVertices_3_bones'>bones</a> should be at most 100.
<a href='#SkCanvas_drawVertices_3_boneCount'>boneCount</a> must be at most 80, and thus the size of <a href='#SkCanvas_drawVertices_3_bones'>bones</a> should be at most 80.
### Parameters
@ -6566,10 +6566,6 @@ it should be the identity matrix.
</tr>
</table>
### Example
<div><fiddle-embed name="7db6ad6b01931d713d7390736239001b"></fiddle-embed></div>
### See Also
<a href='#SkCanvas_drawPatch'>drawPatch</a><sup><a href='#SkCanvas_drawPatch_2'>[2]</a></sup> <a href='#SkCanvas_drawPicture'>drawPicture</a><sup><a href='#SkCanvas_drawPicture_2'>[2]</a></sup><sup><a href='#SkCanvas_drawPicture_3'>[3]</a></sup><sup><a href='#SkCanvas_drawPicture_4'>[4]</a></sup>
@ -6579,7 +6575,7 @@ it should be the identity matrix.
<a name='SkCanvas_drawVertices_4'></a>
<pre style="padding: 1em 1em 1em 1em; width: 62.5em;background-color: #f0f0f0">
void <a href='#SkCanvas_drawVertices'>drawVertices</a>(const <a href='undocumented#sk_sp'>sk sp</a>&lt;<a href='undocumented#SkVertices'>SkVertices</a>&gt;& vertices, const <a href='SkMatrix_Reference#SkMatrix'>SkMatrix</a>* bones, int boneCount,
void <a href='#SkCanvas_drawVertices'>drawVertices</a>(const <a href='undocumented#sk_sp'>sk sp</a>&lt;<a href='undocumented#SkVertices'>SkVertices</a>&gt;& vertices, const <a href='undocumented#SkVertices_Bone'>SkVertices::Bone</a> bones[], int boneCount,
<a href='SkBlendMode_Reference#SkBlendMode'>SkBlendMode</a> mode, const <a href='SkPaint_Reference#SkPaint'>SkPaint</a>& paint)
</pre>
@ -6590,7 +6586,7 @@ contains <a href='undocumented#Shader'>Shader</a>, <a href='SkBlendMode_Referenc
The first element of <a href='#SkCanvas_drawVertices_4_bones'>bones</a> 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.
<a href='#SkCanvas_drawVertices_4_boneCount'>boneCount</a> must be at most 100, and thus the size of <a href='#SkCanvas_drawVertices_4_bones'>bones</a> should be at most 100.
<a href='#SkCanvas_drawVertices_4_boneCount'>boneCount</a> must be at most 80, and thus the size of <a href='#SkCanvas_drawVertices_4_bones'>bones</a> should be at most 80.
### Parameters
@ -6611,10 +6607,6 @@ it should be the identity matrix.
</tr>
</table>
### Example
<div><fiddle-embed name="cc1fc7f3462abc79ec6dec3405e2812d"></fiddle-embed></div>
### See Also
<a href='#SkCanvas_drawPatch'>drawPatch</a><sup><a href='#SkCanvas_drawPatch_2'>[2]</a></sup> <a href='#SkCanvas_drawPicture'>drawPicture</a><sup><a href='#SkCanvas_drawPicture_2'>[2]</a></sup><sup><a href='#SkCanvas_drawPicture_3'>[3]</a></sup><sup><a href='#SkCanvas_drawPicture_4'>[4]</a></sup>

View File

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

View File

@ -645,6 +645,8 @@ bool <a href='#GrBackendTexture_isValid'>isValid</a>() const
# <a name='SkVertices'>Class SkVertices</a>
# <a name='SkVertices_Bone'>Class SkVertices::Bone</a>
## <a name='Colors'>Colors</a>
## <a name='Texs'>Texs</a>

View File

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

View File

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

View File

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

View File

@ -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<SkVertices>& vertices, const SkMatrix* bones, int boneCount,
SkBlendMode mode, const SkPaint& paint) {
void SkCanvas::drawVertices(const sk_sp<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);
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)

View File

@ -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<SkVertices> copy;
if (vertices->hasColors()) {

View File

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

View File

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

View File

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

View File

@ -455,7 +455,7 @@ namespace {
SkBlendMode mode;
SkPaint paint;
void draw(SkCanvas* c, const SkMatrix&) const {
c->drawVertices(vertices, pod<SkMatrix>(this), boneCount, mode, paint);
c->drawVertices(vertices, pod<SkVertices::Bone>(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<DrawPoints>(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<DrawVertices>(boneCount * sizeof(SkMatrix),
void SkLiteDL::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
int boneCount, SkBlendMode mode, const SkPaint& paint) {
void* pod = this->push<DrawVertices>(boneCount * sizeof(SkVertices::Bone),
vertices,
boneCount,
mode,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<uint32_t>(mode));
this->validate(initialOffset, size);

View File

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

View File

@ -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<SkRecords::DrawVertices>(paint,
sk_ref_sp(const_cast<SkVertices*>(vertices)),

View File

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

View File

@ -344,7 +344,7 @@ RECORD(DrawAtlas, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag,
RECORD(DrawVertices, kDraw_Tag|kHasPaint_Tag,
SkPaint paint;
sk_sp<SkVertices> vertices;
PODArray<SkMatrix> bones;
PODArray<SkVertices::Bone> bones;
int boneCount;
SkBlendMode bmode);
RECORD(DrawShadowRec, kDraw_Tag,

View File

@ -207,6 +207,69 @@ uint16_t* SkVertices::Builder::indices() {
return const_cast<uint16_t*>(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> 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<SkVertices> 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> SkVertices::MakeCopy(VertexMode mode, int vertexCount,

View File

@ -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<GrGeometryProcessor> DefaultGeoProc::TestCreate(GrProcessorTestData* d) {

View File

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

View File

@ -839,7 +839,7 @@ void GrRenderTargetContext::drawVertices(const GrClip& clip,
GrPaint&& paint,
const SkMatrix& viewMatrix,
sk_sp<SkVertices> vertices,
const SkMatrix bones[],
const SkVertices::Bone bones[],
int boneCount,
GrPrimitiveType* overridePrimType) {
ASSERT_SINGLE_OWNER

View File

@ -215,7 +215,7 @@ public:
GrPaint&& paint,
const SkMatrix& viewMatrix,
sk_sp<SkVertices> vertices,
const SkMatrix bones[],
const SkVertices::Bone bones[],
int boneCount,
GrPrimitiveType* overridePrimType = nullptr);

View File

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

View File

@ -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<GrRenderTargetContext> MakeRenderTargetContext(GrContext*,

View File

@ -12,12 +12,10 @@
#include "SkGr.h"
#include "SkRectPriv.h"
static constexpr int kNumFloatsPerSkMatrix = 9;
std::unique_ptr<GrDrawOp> GrDrawVerticesOp::Make(GrContext* context,
GrPaint&& paint,
sk_sp<SkVertices> vertices,
const SkMatrix bones[],
const SkVertices::Bone bones[],
int boneCount,
const SkMatrix& viewMatrix,
GrAAType aaType,
@ -32,7 +30,7 @@ std::unique_ptr<GrDrawOp> GrDrawVerticesOp::Make(GrContext* context,
}
GrDrawVerticesOp::GrDrawVerticesOp(const Helper::MakeArgs& helperArgs, GrColor color,
sk_sp<SkVertices> vertices, const SkMatrix bones[],
sk_sp<SkVertices> vertices, const SkVertices::Bone bones[],
int boneCount, GrPrimitiveType primitiveType, GrAAType aaType,
sk_sp<GrColorSpaceXform> 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<GrGeometryProcessor> 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<const float*>(fBones.data()), fBones.size());
*hasBoneAttribute = this->hasBones();
if (this->hasBones()) {

View File

@ -38,16 +38,16 @@ public:
static std::unique_ptr<GrDrawOp> Make(GrContext* context,
GrPaint&&,
sk_sp<SkVertices>,
const SkMatrix bones[],
const SkVertices::Bone bones[],
int boneCount,
const SkMatrix& viewMatrix,
GrAAType,
sk_sp<GrColorSpaceXform>,
GrPrimitiveType* overridePrimType = nullptr);
GrDrawVerticesOp(const Helper::MakeArgs&, GrColor, sk_sp<SkVertices>, const SkMatrix bones[],
int boneCount, GrPrimitiveType, GrAAType, sk_sp<GrColorSpaceXform>,
const SkMatrix& viewMatrix);
GrDrawVerticesOp(const Helper::MakeArgs&, GrColor, sk_sp<SkVertices>,
const SkVertices::Bone bones[], int boneCount, GrPrimitiveType, GrAAType,
sk_sp<GrColorSpaceXform>, 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<SkVertices> fVertices;
std::vector<float> 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<SkVertices::Bone> 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;

View File

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

View File

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

View File

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

View File

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

View File

@ -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<SkMatrix>(boneCount) : nullptr;
const SkVertices::Bone* bones = boneCount ? reader.skipT<SkVertices::Bone>(boneCount) : nullptr;
if (vertices) {
canvas->drawVertices(vertices, bones, boneCount, bmode, read_paint(reader));
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<SkVertices*>(vertices)),

View File

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

View File

@ -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<std::string>.
@ -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<SkVertices> 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<uint32_t>(attrBoneIdx[k]);
fBoneWgt[i].weights[k] = attrBoneWgt[k];
fBoneIdx[i][k] = static_cast<uint32_t>(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<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(),
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<SkVertices::BoneWeights> fBoneWgt;
std::vector<uint16_t> fIndices;
std::vector<SkMatrix> fBones;
sk_sp<SkVertices> fVertices;
std::vector<SkVertices::Bone> fBones;
sk_sp<SkVertices> fVertices;
uint32_t fRenderFlags;
};