Ruiqi Mao | b609e6d | 2018-07-17 10:19:38 -0400 | [diff] [blame^] | 1 | /* |
| 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 | |
| 15 | using namespace skiagm; |
| 16 | |
| 17 | static const int kCellSize = 60; |
| 18 | static const int kColumnSize = 36; |
| 19 | |
| 20 | static const int kBoneCount = 7; |
| 21 | static 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 | |
| 31 | static const int kVertexCount = 4; |
| 32 | static const SkPoint kPositions[] = { |
| 33 | { 0, 0 }, |
| 34 | { 0, 30 }, |
| 35 | { 30, 30 }, |
| 36 | { 30, 0 }, |
| 37 | }; |
| 38 | static const SkColor kColors[] = { |
| 39 | 0xFFFF0000, |
| 40 | 0xFF00FF00, |
| 41 | 0xFF0000FF, |
| 42 | 0xFFFFFF00, |
| 43 | }; |
| 44 | static 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 | }; |
| 50 | static 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 | |
| 57 | static const int kIndexCount = 6; |
| 58 | static const uint16_t kIndices[] = { |
| 59 | 0, 1, 2, |
| 60 | 2, 3, 0, |
| 61 | }; |
| 62 | |
| 63 | // Swap two SkMatrix pointers in place. |
| 64 | static void swap(const SkMatrix** x, const SkMatrix** y) { |
| 65 | const SkMatrix* temp = *x; |
| 66 | *x = *y; |
| 67 | *y = temp; |
| 68 | } |
| 69 | |
| 70 | class SkinningGM : public GM { |
| 71 | |
| 72 | public: |
| 73 | SkinningGM(bool deformUsingCPU) |
| 74 | : fPaint() |
| 75 | , fVertices(nullptr) |
| 76 | , fDeformUsingCPU(deformUsingCPU) |
| 77 | {} |
| 78 | |
| 79 | protected: |
| 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 | |
| 124 | private: |
| 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 | |
| 217 | private: |
| 218 | SkPaint fPaint; |
| 219 | sk_sp<SkVertices> fVertices; |
| 220 | bool fDeformUsingCPU; |
| 221 | |
| 222 | typedef GM INHERITED; |
| 223 | }; |
| 224 | |
| 225 | ///////////////////////////////////////////////////////////////////////////////////// |
| 226 | |
| 227 | DEF_GM(return new SkinningGM(true);) |
| 228 | DEF_GM(return new SkinningGM(false);) |