blob: 4ac7d86137773ee53370c5bba59bc518b81d46ae [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
8#include "Nima.h"
9
10#include "SkString.h"
11#include "SkVertices.h"
12#include "SkPaint.h"
13#include "Resources.h"
14#include <algorithm>
15
16#include <iostream>
17
18using namespace nima;
19
20SampleActor::SampleActor(std::string baseName)
21 : fTexture(nullptr)
22 , fActorImages()
23 , fPaint(nullptr) {
24 // Load the NIMA data.
25 SkString nimaSkPath = GetResourcePath(("nima/" + baseName + ".nima").c_str());
26 std::string nimaPath(nimaSkPath.c_str());
27 INHERITED::load(nimaPath);
28
29 // Load the image asset.
30 fTexture = GetResourceAsImage(("nima/" + baseName + ".png").c_str());
31
32 // Create the paint.
33 fPaint = std::make_unique<SkPaint>();
34 fPaint->setShader(fTexture->makeShader(nullptr));
35
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
92 // Deform the position.
93 Vec2D position(attrPosition[0], attrPosition[1]);
94 if (fActorImage->connectedBoneCount() > 0) {
95 position = deform(position, attrBoneIdx, attrBoneWgt);
96 } else {
97 position = deform(position, nullptr, nullptr);
98 }
99
100 // Set the data.
101 positions[i].set(position[0], position[1]);
102 texs[i].set(attrTex[0] * fTexture->width(), attrTex[1] * fTexture->height());
103 }
104
105 // Create vertices.
106 sk_sp<SkVertices> vertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode,
107 vertexCount,
108 positions.data(),
109 texs.data(),
110 nullptr,
111 indexCount,
112 indexData);
113
114 // Determine the blend mode.
115 SkBlendMode blendMode;
116 switch (fActorImage->blendMode()) {
117 case BlendMode::Off: {
118 blendMode = SkBlendMode::kSrc;
119 break;
120 }
121 case BlendMode::Normal: {
122 blendMode = SkBlendMode::kSrcOver;
123 break;
124 }
125 case BlendMode::Additive: {
126 blendMode = SkBlendMode::kPlus;
127 break;
128 }
129 case BlendMode::Multiply: {
130 blendMode = SkBlendMode::kMultiply;
131 break;
132 }
133 case BlendMode::Screen: {
134 blendMode = SkBlendMode::kScreen;
135 break;
136 }
137 }
138
139 // Set the opacity.
140 fPaint->setAlpha(static_cast<U8CPU>(fActorImage->renderOpacity() * 255));
141
142 // Draw the vertices.
143 canvas->drawVertices(vertices, blendMode, *fPaint);
144
145 // Reset the opacity.
146 fPaint->setAlpha(255);
147}
148
149Vec2D SampleActorImage::deform(const Vec2D& position, float* boneIdx, float* boneWgt) const {
150 float px = position[0], py = position[1];
151 float px2 = px, py2 = py;
152 float influence[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
153
154 // Apply the world transform.
155 Mat2D worldTransform = fActorImage->worldTransform();
156 px2 = worldTransform[0] * px + worldTransform[2] * py + worldTransform[4];
157 py2 = worldTransform[1] * px + worldTransform[3] * py + worldTransform[5];
158
159 // Apply deformations based on bone offsets.
160 if (boneIdx && boneWgt) {
161 float* matrices = fActorImage->boneInfluenceMatrices();
162
163 for (uint32_t i = 0; i < 4; i ++) {
164 int index = static_cast<int>(boneIdx[i]);
165 float weight = boneWgt[i];
166 for (int j = 0; j < 6; j ++) {
167 influence[j] += matrices[index * 6 + j] * weight;
168 }
169 }
170
171 px = influence[0] * px2 + influence[2] * py2 + influence[4];
172 py = influence[1] * px2 + influence[3] * py2 + influence[5];
173 } else {
174 px = px2;
175 py = py2;
176 }
177
178 // Return the transformed position.
179 return Vec2D(px, py);
180}