blob: 4634a45199a0451d33c7b8a133725d3e68e71235 [file] [log] [blame]
Brian Osmanc069a572018-06-19 16:05:09 -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
Ruiqi Maoc5c3df62018-06-21 14:40:28 -04008#include "SampleNimaActor.h"
Brian Osmanc069a572018-06-19 16:05:09 -04009
10#include "SkString.h"
11#include "SkVertices.h"
12#include "SkPaint.h"
Ruiqi Mao9ac1b722018-06-21 11:24:13 -040013#include "SkFilterQuality.h"
Brian Osmanc069a572018-06-19 16:05:09 -040014#include "Resources.h"
15#include <algorithm>
16
Brian Osmanc069a572018-06-19 16:05:09 -040017using namespace nima;
18
19SampleActor::SampleActor(std::string baseName)
20 : fTexture(nullptr)
21 , fActorImages()
22 , fPaint(nullptr) {
23 // Load the NIMA data.
24 SkString nimaSkPath = GetResourcePath(("nima/" + baseName + ".nima").c_str());
25 std::string nimaPath(nimaSkPath.c_str());
26 INHERITED::load(nimaPath);
27
28 // Load the image asset.
29 fTexture = GetResourceAsImage(("nima/" + baseName + ".png").c_str());
30
31 // Create the paint.
32 fPaint = std::make_unique<SkPaint>();
33 fPaint->setShader(fTexture->makeShader(nullptr));
Ruiqi Mao9ac1b722018-06-21 11:24:13 -040034 fPaint->setFilterQuality(SkFilterQuality::kLow_SkFilterQuality);
Brian Osmanc069a572018-06-19 16:05:09 -040035
36 // Load the image nodes.
37 fActorImages.reserve(m_ImageNodeCount);
38 for (uint32_t i = 0; i < m_ImageNodeCount; i ++) {
39 fActorImages.emplace_back(m_ImageNodes[i], fTexture, fPaint.get());
40 }
41
42 // Sort the image nodes.
43 std::sort(fActorImages.begin(), fActorImages.end(), [](auto a, auto b) {
44 return a.drawOrder() < b.drawOrder();
45 });
46}
47
48SampleActor::~SampleActor() {
49}
50
51void SampleActor::render(SkCanvas* canvas) const {
52 // Render the image nodes.
53 for (auto image : fActorImages) {
54 image.render(this, canvas);
55 }
56}
57
58SampleActorImage::SampleActorImage(ActorImage* actorImage, sk_sp<SkImage> texture, SkPaint* paint)
59 : fActorImage(actorImage)
60 , fTexture(texture)
61 , fPaint(paint) {
62}
63
64SampleActorImage::~SampleActorImage() {
65}
66
67void SampleActorImage::render(const SampleActor* actor, SkCanvas* canvas) const {
68 // Retrieve data from the image.
69 uint32_t vertexCount = fActorImage->vertexCount();
70 uint32_t vertexStride = fActorImage->vertexStride();
71 float* vertexData = fActorImage->vertices();
72 uint32_t indexCount = fActorImage->triangleCount() * 3;
73 uint16_t* indexData = fActorImage->triangles();
74
75 // Don't render if not visible.
76 if (!vertexCount || fActorImage->textureIndex() < 0) {
77 return;
78 }
79
80 // Split the vertex data.
81 std::vector<SkPoint> positions(vertexCount);
82 std::vector<SkPoint> texs(vertexCount);
83 for (uint32_t i = 0; i < vertexCount; i ++) {
84 uint32_t j = i * vertexStride;
85
86 // Get the attributes.
87 float* attrPosition = vertexData + j;
88 float* attrTex = vertexData + j + 2;
89 float* attrBoneIdx = vertexData + j + 4;
90 float* attrBoneWgt = vertexData + j + 8;
91
Ruiqi Mao9ac1b722018-06-21 11:24:13 -040092 // Get deformed positions if necessary.
93 if (fActorImage->doesAnimationVertexDeform()) {
94 attrPosition = fActorImage->animationDeformedVertices() + i * 2;
95 }
96
Brian Osmanc069a572018-06-19 16:05:09 -040097 // Deform the position.
98 Vec2D position(attrPosition[0], attrPosition[1]);
99 if (fActorImage->connectedBoneCount() > 0) {
100 position = deform(position, attrBoneIdx, attrBoneWgt);
101 } else {
102 position = deform(position, nullptr, nullptr);
103 }
104
105 // Set the data.
106 positions[i].set(position[0], position[1]);
107 texs[i].set(attrTex[0] * fTexture->width(), attrTex[1] * fTexture->height());
108 }
109
110 // Create vertices.
111 sk_sp<SkVertices> vertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode,
112 vertexCount,
113 positions.data(),
114 texs.data(),
115 nullptr,
116 indexCount,
117 indexData);
118
119 // Determine the blend mode.
120 SkBlendMode blendMode;
121 switch (fActorImage->blendMode()) {
122 case BlendMode::Off: {
123 blendMode = SkBlendMode::kSrc;
124 break;
125 }
126 case BlendMode::Normal: {
127 blendMode = SkBlendMode::kSrcOver;
128 break;
129 }
130 case BlendMode::Additive: {
131 blendMode = SkBlendMode::kPlus;
132 break;
133 }
134 case BlendMode::Multiply: {
135 blendMode = SkBlendMode::kMultiply;
136 break;
137 }
138 case BlendMode::Screen: {
139 blendMode = SkBlendMode::kScreen;
140 break;
141 }
142 }
143
144 // Set the opacity.
145 fPaint->setAlpha(static_cast<U8CPU>(fActorImage->renderOpacity() * 255));
146
147 // Draw the vertices.
148 canvas->drawVertices(vertices, blendMode, *fPaint);
149
150 // Reset the opacity.
151 fPaint->setAlpha(255);
152}
153
154Vec2D SampleActorImage::deform(const Vec2D& position, float* boneIdx, float* boneWgt) const {
155 float px = position[0], py = position[1];
156 float px2 = px, py2 = py;
157 float influence[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
158
159 // Apply the world transform.
160 Mat2D worldTransform = fActorImage->worldTransform();
161 px2 = worldTransform[0] * px + worldTransform[2] * py + worldTransform[4];
162 py2 = worldTransform[1] * px + worldTransform[3] * py + worldTransform[5];
163
164 // Apply deformations based on bone offsets.
165 if (boneIdx && boneWgt) {
166 float* matrices = fActorImage->boneInfluenceMatrices();
167
168 for (uint32_t i = 0; i < 4; i ++) {
169 int index = static_cast<int>(boneIdx[i]);
170 float weight = boneWgt[i];
171 for (int j = 0; j < 6; j ++) {
172 influence[j] += matrices[index * 6 + j] * weight;
173 }
174 }
175
176 px = influence[0] * px2 + influence[2] * py2 + influence[4];
177 py = influence[1] * px2 + influence[3] * py2 + influence[5];
178 } else {
179 px = px2;
180 py = py2;
181 }
182
183 // Return the transformed position.
184 return Vec2D(px, py);
185}