blob: 9b59594dc4d9c10c16b8e396c0f9fd811de3a799 [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:
Ruiqi Mao363402d2018-07-18 10:53:44 -040073 SkinningGM(bool deformUsingCPU, bool cache)
Ruiqi Maob609e6d2018-07-17 10:19:38 -040074 : fPaint()
75 , fVertices(nullptr)
76 , fDeformUsingCPU(deformUsingCPU)
Ruiqi Mao363402d2018-07-18 10:53:44 -040077 , fCache(cache)
Ruiqi Maob609e6d2018-07-17 10:19:38 -040078 {}
79
80protected:
81 bool runAsBench() const override {
82 return true;
83 }
84
85 SkString onShortName() override {
86 SkString name("skinning");
87 if (fDeformUsingCPU) {
88 name.append("_cpu");
89 }
Ruiqi Mao363402d2018-07-18 10:53:44 -040090 if (fCache) {
91 name.append("_cached");
92 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -040093 return name;
94 }
95
96 SkISize onISize() override {
97 return SkISize::Make(2400, 2400);
98 }
99
100 void onOnceBeforeDraw() override {
101 fVertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode,
102 kVertexCount,
103 kPositions,
104 nullptr,
105 kColors,
106 kBoneIndices,
107 kBoneWeights,
108 kIndexCount,
109 kIndices,
Ruiqi Mao363402d2018-07-18 10:53:44 -0400110 !fCache);
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400111 }
112
113 void onDraw(SkCanvas* canvas) override {
114 // Set the initial position.
115 int xpos = kCellSize;
116 int ypos = kCellSize;
117
118 // Create the mutable set of bones.
119 const SkMatrix* bones[kBoneCount];
120 for (int i = 0; i < kBoneCount; i ++) {
121 bones[i] = &kBones[i];
122 }
123
124 // Draw the vertices.
125 drawPermutations(canvas, xpos, ypos, bones, 1);
126 }
127
128private:
129 void drawPermutations(SkCanvas* canvas,
130 int& xpos,
131 int& ypos,
132 const SkMatrix** bones,
133 int start) {
134 if (start == kBoneCount) {
135 // Reached the end of the permutations, so draw.
136 canvas->save();
137
138 // Copy the bones.
139 SkMatrix copiedBones[kBoneCount];
140 for (int i = 0; i < kBoneCount; i ++) {
141 copiedBones[i] = *bones[i];
142 }
143
144 // Set the position.
145 canvas->translate(xpos, ypos);
146
147 // Draw the vertices.
148 if (fDeformUsingCPU) {
149 // Deform with CPU.
150 std::vector<SkPoint> positions(kVertexCount);
151 for (int i = 0; i < kVertexCount; i ++) {
152 const SkVertices::BoneIndices& indices = kBoneIndices[i];
153 const SkVertices::BoneWeights& weights = kBoneWeights[i];
154
155 // Apply deformations.
156 SkPoint& result = positions[i];
157 SkPoint transformed;
158 for (uint32_t j = 0; j < 4; j ++) {
159 // Get the bone attachment data.
160 uint32_t index = indices.indices[j];
161 float weight = weights.weights[j];
162
163 // Skip the bone is there is no weight.
164 if (weight == 0.0f) {
165 continue;
166 }
167 SkASSERT(index != 0);
168
169 // transformed = M * v
170 copiedBones[index].mapPoints(&transformed, &kPositions[i], 1);
171
172 // result += transformed * w
173 result += transformed * weight;
174 }
175 }
176
177 sk_sp<SkVertices> vertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode,
178 kVertexCount,
179 positions.data(),
180 nullptr,
181 kColors,
182 kIndexCount,
Ruiqi Mao363402d2018-07-18 10:53:44 -0400183 kIndices,
184 !fCache);
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400185 canvas->drawVertices(vertices.get(),
186 SkBlendMode::kSrc,
187 fPaint);
188 } else {
189 // Deform with GPU.
190 canvas->drawVertices(fVertices.get(),
191 copiedBones,
192 kBoneCount,
193 SkBlendMode::kSrc,
194 fPaint);
195 }
196
197 canvas->restore();
198
199 // Get a new position to draw the vertices.
200 xpos += kCellSize;
201 if (xpos > kCellSize * kColumnSize) {
202 xpos = kCellSize;
203 ypos += kCellSize;
204 }
205
206 return;
207 }
208
209 // Find all possible permutations within the given range.
210 for (int i = start; i < kBoneCount; i ++) {
211 // Swap the start and i-th elements.
212 swap(bones + start, bones + i);
213
214 // Find permutations of the sub array.
215 drawPermutations(canvas, xpos, ypos, bones, start + 1);
216
217 // Swap the elements back.
218 swap(bones + i, bones + start);
219 }
220 }
221
222private:
223 SkPaint fPaint;
224 sk_sp<SkVertices> fVertices;
225 bool fDeformUsingCPU;
Ruiqi Mao363402d2018-07-18 10:53:44 -0400226 bool fCache;
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400227
228 typedef GM INHERITED;
229};
230
231/////////////////////////////////////////////////////////////////////////////////////
232
Ruiqi Mao363402d2018-07-18 10:53:44 -0400233DEF_GM(return new SkinningGM(true, true);)
234DEF_GM(return new SkinningGM(false, true);)
235DEF_GM(return new SkinningGM(true, false);)
236DEF_GM(return new SkinningGM(false, false);)