blob: 101522fa48e576fd55d3f15a078734b456de9ee1 [file] [log] [blame]
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "gm.h"
9#include "SkCanvas.h"
10#include "SkVertices.h"
11#include "SkPoint.h"
12#include <iostream>
13#include <vector>
14
15using namespace skiagm;
16
17static const int kCellSize = 60;
18static const int kColumnSize = 36;
19
20static const int kBoneCount = 7;
21static const SkMatrix kBones[] = {
22 SkMatrix::I(),
23 SkMatrix::MakeTrans(10, 0),
24 SkMatrix::MakeTrans(0, 10),
25 SkMatrix::MakeTrans(-10, 0),
26 SkMatrix::MakeTrans(0, -10),
27 SkMatrix::MakeScale(0.5f),
28 SkMatrix::MakeScale(1.5f),
29};
30
31static const int kVertexCount = 4;
32static const SkPoint kPositions[] = {
33 { 0, 0 },
34 { 0, 30 },
35 { 30, 30 },
36 { 30, 0 },
37};
38static const SkColor kColors[] = {
39 0xFFFF0000,
40 0xFF00FF00,
41 0xFF0000FF,
42 0xFFFFFF00,
43};
44static const SkVertices::BoneIndices kBoneIndices[] = {
45 {{ 1, 0, 0, 0 }},
46 {{ 2, 1, 0, 0 }},
47 {{ 3, 2, 1, 0 }},
48 {{ 4, 3, 2, 1 }},
49};
50static const SkVertices::BoneWeights kBoneWeights[] = {
51 {{ 1.0f, 0.0f, 0.0f, 0.0f }},
52 {{ 0.5f, 0.5f, 0.0f, 0.0f }},
53 {{ 0.34f, 0.33f, 0.33f, 0.0f }},
54 {{ 0.25f, 0.25f, 0.25f, 0.25f }},
55};
56
57static const int kIndexCount = 6;
58static const uint16_t kIndices[] = {
59 0, 1, 2,
60 2, 3, 0,
61};
62
63// Swap two SkMatrix pointers in place.
64static void swap(const SkMatrix** x, const SkMatrix** y) {
65 const SkMatrix* temp = *x;
66 *x = *y;
67 *y = temp;
68}
69
70class SkinningGM : public GM {
71
72public:
73 SkinningGM(bool deformUsingCPU)
74 : fPaint()
75 , fVertices(nullptr)
76 , fDeformUsingCPU(deformUsingCPU)
77 {}
78
79protected:
80 bool runAsBench() const override {
81 return true;
82 }
83
84 SkString onShortName() override {
85 SkString name("skinning");
86 if (fDeformUsingCPU) {
87 name.append("_cpu");
88 }
89 return name;
90 }
91
92 SkISize onISize() override {
93 return SkISize::Make(2400, 2400);
94 }
95
96 void onOnceBeforeDraw() override {
97 fVertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode,
98 kVertexCount,
99 kPositions,
100 nullptr,
101 kColors,
102 kBoneIndices,
103 kBoneWeights,
104 kIndexCount,
105 kIndices,
106 false); // Keep the vertices non-volatile.
107 }
108
109 void onDraw(SkCanvas* canvas) override {
110 // Set the initial position.
111 int xpos = kCellSize;
112 int ypos = kCellSize;
113
114 // Create the mutable set of bones.
115 const SkMatrix* bones[kBoneCount];
116 for (int i = 0; i < kBoneCount; i ++) {
117 bones[i] = &kBones[i];
118 }
119
120 // Draw the vertices.
121 drawPermutations(canvas, xpos, ypos, bones, 1);
122 }
123
124private:
125 void drawPermutations(SkCanvas* canvas,
126 int& xpos,
127 int& ypos,
128 const SkMatrix** bones,
129 int start) {
130 if (start == kBoneCount) {
131 // Reached the end of the permutations, so draw.
132 canvas->save();
133
134 // Copy the bones.
135 SkMatrix copiedBones[kBoneCount];
136 for (int i = 0; i < kBoneCount; i ++) {
137 copiedBones[i] = *bones[i];
138 }
139
140 // Set the position.
141 canvas->translate(xpos, ypos);
142
143 // Draw the vertices.
144 if (fDeformUsingCPU) {
145 // Deform with CPU.
146 std::vector<SkPoint> positions(kVertexCount);
147 for (int i = 0; i < kVertexCount; i ++) {
148 const SkVertices::BoneIndices& indices = kBoneIndices[i];
149 const SkVertices::BoneWeights& weights = kBoneWeights[i];
150
151 // Apply deformations.
152 SkPoint& result = positions[i];
153 SkPoint transformed;
154 for (uint32_t j = 0; j < 4; j ++) {
155 // Get the bone attachment data.
156 uint32_t index = indices.indices[j];
157 float weight = weights.weights[j];
158
159 // Skip the bone is there is no weight.
160 if (weight == 0.0f) {
161 continue;
162 }
163 SkASSERT(index != 0);
164
165 // transformed = M * v
166 copiedBones[index].mapPoints(&transformed, &kPositions[i], 1);
167
168 // result += transformed * w
169 result += transformed * weight;
170 }
171 }
172
173 sk_sp<SkVertices> vertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode,
174 kVertexCount,
175 positions.data(),
176 nullptr,
177 kColors,
178 kIndexCount,
179 kIndices);
180 canvas->drawVertices(vertices.get(),
181 SkBlendMode::kSrc,
182 fPaint);
183 } else {
184 // Deform with GPU.
185 canvas->drawVertices(fVertices.get(),
186 copiedBones,
187 kBoneCount,
188 SkBlendMode::kSrc,
189 fPaint);
190 }
191
192 canvas->restore();
193
194 // Get a new position to draw the vertices.
195 xpos += kCellSize;
196 if (xpos > kCellSize * kColumnSize) {
197 xpos = kCellSize;
198 ypos += kCellSize;
199 }
200
201 return;
202 }
203
204 // Find all possible permutations within the given range.
205 for (int i = start; i < kBoneCount; i ++) {
206 // Swap the start and i-th elements.
207 swap(bones + start, bones + i);
208
209 // Find permutations of the sub array.
210 drawPermutations(canvas, xpos, ypos, bones, start + 1);
211
212 // Swap the elements back.
213 swap(bones + i, bones + start);
214 }
215 }
216
217private:
218 SkPaint fPaint;
219 sk_sp<SkVertices> fVertices;
220 bool fDeformUsingCPU;
221
222 typedef GM INHERITED;
223};
224
225/////////////////////////////////////////////////////////////////////////////////////
226
227DEF_GM(return new SkinningGM(true);)
228DEF_GM(return new SkinningGM(false);)