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 "NimaActor.h" 9 10 #include "SkData.h" 11 #include "SkFilterQuality.h" 12 #include "SkImage.h" 13 #include "SkPaint.h" 14 #include "SkString.h" 15 #include "SkVertices.h" 16 17 #include <algorithm> 18 #include <cmath> 19 20 NimaActor::NimaActor(std::string nimaPath, std::string texturePath) 21 : fTexture(nullptr) 22 , fActorImages() 23 , fPaint(nullptr) 24 , fAnimationNames() 25 , fAnimationInstance(nullptr) { 26 // Load the NIMA data. 27 INHERITED::load(nimaPath); 28 29 // Load the image asset. 30 fTexture = SkImage::MakeFromEncoded(SkData::MakeFromFileName(texturePath.c_str())); 31 32 this->init(); 33 } 34 35 NimaActor::NimaActor(sk_sp<SkData> nimaBytes, sk_sp<SkData> textureBytes) 36 : fTexture(nullptr) 37 , fActorImages() 38 , fPaint(nullptr) 39 , fAnimationNames() 40 , fAnimationInstance(nullptr) { 41 // Load the NIMA data. 42 INHERITED::load(const_cast<uint8_t*>(nimaBytes->bytes()), nimaBytes->size()); 43 44 // Load the image asset. 45 fTexture = SkImage::MakeFromEncoded(textureBytes); 46 47 this->init(); 48 } 49 50 void NimaActor::init() { 51 // Create the paint. 52 fPaint = std::make_unique<SkPaint>(); 53 fPaint->setShader(fTexture->makeShader(nullptr)); 54 fPaint->setFilterQuality(SkFilterQuality::kLow_SkFilterQuality); 55 56 // Load the image nodes. 57 fActorImages.reserve(m_ImageNodeCount); 58 for (uint32_t i = 0; i < m_ImageNodeCount; i ++) { 59 fActorImages.emplace_back(m_ImageNodes[i], fTexture.get(), fPaint.get()); 60 } 61 62 // Sort the image nodes. 63 std::sort(fActorImages.begin(), fActorImages.end(), [](auto a, auto b) { 64 return a.drawOrder() < b.drawOrder(); 65 }); 66 67 // Get the list of animations. 68 fAnimationNames.reserve(m_AnimationsCount); 69 for (uint32_t i = 0; i < m_AnimationsCount; i++) { 70 fAnimationNames.push_back(m_Animations[i].name()); 71 } 72 this->setAnimation(0); 73 } 74 75 SkScalar NimaActor::duration() const { 76 if (fAnimationInstance) { 77 return fAnimationInstance->duration(); 78 } 79 return 0.0f; 80 } 81 82 void NimaActor::setAnimation(uint8_t index) { 83 if (index < fAnimationNames.size()) { 84 fAnimationIndex = index; 85 fAnimationInstance = this->animationInstance(fAnimationNames[fAnimationIndex]); 86 } 87 } 88 89 void NimaActor::setAnimation(std::string name) { 90 for (size_t i = 0; i < fAnimationNames.size(); i++) 91 { 92 std::string aName = fAnimationNames[i]; 93 if (aName == name) 94 { 95 setAnimation(i); 96 return; 97 } 98 } 99 } 100 101 void NimaActor::render(SkCanvas* canvas, uint32_t renderFlags) { 102 // Render the image nodes. 103 for (auto& image : fActorImages) { 104 image.render(canvas, renderFlags); 105 } 106 } 107 108 void NimaActor::seek(SkScalar t) { 109 // Apply the animation. 110 if (fAnimationInstance) { 111 t = std::fmod(t, fAnimationInstance->max()); 112 fAnimationInstance->time(t); 113 fAnimationInstance->apply(1.0f); 114 } 115 } 116 117 // =================================================================================== 118 119 NimaActorImage::NimaActorImage(nima::ActorImage* actorImage, SkImage* texture, SkPaint* paint) 120 : fActorImage(actorImage) 121 , fTexture(texture) 122 , fPaint(paint) 123 , fSkinned(false) 124 , fPositions() 125 , fTexs() 126 , fBoneIdx() 127 , fBoneWgt() 128 , fIndices() 129 , fBones() 130 , fVertices(nullptr) 131 , fRenderFlags(0) { 132 // Update the vertices and bones. 133 this->updateVertices(true); 134 this->updateBones(); 135 } 136 137 void NimaActorImage::render(SkCanvas* canvas, uint32_t renderFlags) { 138 bool dirty = renderFlags != fRenderFlags; 139 fRenderFlags = renderFlags; 140 141 bool useImmediate = renderFlags & kImmediate_RenderFlag; 142 bool useCache = renderFlags & kCache_RenderFlag; 143 bool drawBounds = renderFlags & kBounds_RenderFlag; 144 145 // Don't use the cache if drawing in immediate mode. 146 useCache &= !useImmediate; 147 148 if (fActorImage->doesAnimationVertexDeform() || dirty) { 149 // These are vertices that transform beyond just bone transforms, so they must be 150 // updated every frame. 151 // If the render flags are dirty, reset the vertices object. 152 this->updateVertices(!useCache); 153 } 154 155 // Update the bones. 156 this->updateBones(); 157 158 // Deform the bones in immediate mode. 159 sk_sp<SkVertices> vertices = fVertices; 160 if (useImmediate) { 161 vertices = fVertices->applyBones(fBones.data(), fBones.size()); 162 } 163 164 // Draw the vertices object. 165 this->drawVerticesObject(vertices.get(), canvas, !useImmediate); 166 167 // Draw the bounds. 168 if (drawBounds && fActorImage->renderOpacity() > 0.0f) { 169 // Get the bounds. 170 SkRect bounds = vertices->bounds(); 171 172 // Approximate bounds if not using immediate transforms. 173 if (!useImmediate) { 174 const SkRect originalBounds = fBones[0].mapRect(vertices->bounds()); 175 bounds = originalBounds; 176 for (size_t i = 1; i < fBones.size(); i++) { 177 const SkVertices::Bone& matrix = fBones[i]; 178 bounds.join(matrix.mapRect(originalBounds)); 179 } 180 } 181 182 // Draw the bounds. 183 SkPaint paint; 184 paint.setStyle(SkPaint::kStroke_Style); 185 paint.setColor(0xFFFF0000); 186 canvas->drawRect(bounds, paint); 187 } 188 } 189 190 void NimaActorImage::updateVertices(bool isVolatile) { 191 // Update whether the image is skinned. 192 fSkinned = fActorImage->connectedBoneCount() > 0; 193 194 // Retrieve data from the image. 195 uint32_t vertexCount = fActorImage->vertexCount(); 196 uint32_t vertexStride = fActorImage->vertexStride(); 197 float* vertexData = fActorImage->vertices(); 198 uint32_t indexCount = fActorImage->triangleCount() * 3; 199 uint16_t* indexData = fActorImage->triangles(); 200 201 // Don't render if not visible. 202 if (!vertexCount || fActorImage->textureIndex() < 0) { 203 fPositions.clear(); 204 fTexs.clear(); 205 fBoneIdx.clear(); 206 fBoneWgt.clear(); 207 fIndices.clear(); 208 return; 209 } 210 211 // Split the vertex data. 212 fPositions.resize(vertexCount); 213 fTexs.resize(vertexCount); 214 fIndices.resize(indexCount); 215 if (fSkinned) { 216 fBoneIdx.resize(vertexCount * 4); 217 fBoneWgt.resize(vertexCount * 4); 218 } 219 for (uint32_t i = 0; i < vertexCount; i ++) { 220 uint32_t j = i * vertexStride; 221 222 // Get the attributes. 223 float* attrPosition = vertexData + j; 224 float* attrTex = vertexData + j + 2; 225 float* attrBoneIdx = vertexData + j + 4; 226 float* attrBoneWgt = vertexData + j + 8; 227 228 // Get deformed positions if necessary. 229 if (fActorImage->doesAnimationVertexDeform()) { 230 attrPosition = fActorImage->animationDeformedVertices() + i * 2; 231 } 232 233 // Set the data. 234 fPositions[i].set(attrPosition[0], attrPosition[1]); 235 fTexs[i].set(attrTex[0] * fTexture->width(), attrTex[1] * fTexture->height()); 236 if (fSkinned) { 237 for (uint32_t k = 0; k < 4; k ++) { 238 fBoneIdx[i][k] = static_cast<uint32_t>(attrBoneIdx[k]); 239 fBoneWgt[i][k] = attrBoneWgt[k]; 240 } 241 } 242 } 243 memcpy(fIndices.data(), indexData, indexCount * sizeof(uint16_t)); 244 245 // Update the vertices object. 246 fVertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, 247 vertexCount, 248 fPositions.data(), 249 fTexs.data(), 250 nullptr, 251 fBoneIdx.data(), 252 fBoneWgt.data(), 253 fIndices.size(), 254 fIndices.data(), 255 isVolatile); 256 } 257 258 void NimaActorImage::updateBones() { 259 // NIMA matrices are a collection of 6 floats. 260 constexpr int kNIMAMatrixSize = 6; 261 262 // Set up the matrices for the first time. 263 if (fBones.size() == 0) { 264 int numMatrices = 1; 265 if (fSkinned) { 266 numMatrices = fActorImage->boneInfluenceMatricesLength() / kNIMAMatrixSize; 267 } 268 269 // Initialize all matrices to the identity matrix. 270 fBones.assign(numMatrices, {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }}); 271 } 272 273 if (fSkinned) { 274 // Update the matrices. 275 float* matrixData = fActorImage->boneInfluenceMatrices(); 276 memcpy(fBones.data(), matrixData, fBones.size() * kNIMAMatrixSize * sizeof(float)); 277 } 278 279 // Set the zero matrix to be the world transform. 280 memcpy(fBones.data(), 281 fActorImage->worldTransform().values(), 282 kNIMAMatrixSize * sizeof(float)); 283 } 284 285 void NimaActorImage::drawVerticesObject(SkVertices* vertices, SkCanvas* canvas, bool useBones) const { 286 // Determine the blend mode. 287 SkBlendMode blendMode; 288 switch (fActorImage->blendMode()) { 289 case nima::BlendMode::Off: { 290 blendMode = SkBlendMode::kSrc; 291 break; 292 } 293 case nima::BlendMode::Normal: { 294 blendMode = SkBlendMode::kSrcOver; 295 break; 296 } 297 case nima::BlendMode::Additive: { 298 blendMode = SkBlendMode::kPlus; 299 break; 300 } 301 case nima::BlendMode::Multiply: { 302 blendMode = SkBlendMode::kMultiply; 303 break; 304 } 305 case nima::BlendMode::Screen: { 306 blendMode = SkBlendMode::kScreen; 307 break; 308 } 309 } 310 311 // Set the opacity. 312 fPaint->setAlpha(static_cast<U8CPU>(fActorImage->renderOpacity() * 255)); 313 314 // Draw the vertices. 315 if (useBones) { 316 canvas->drawVertices(vertices, fBones.data(), fBones.size(), blendMode, *fPaint); 317 } else { 318 canvas->drawVertices(vertices, blendMode, *fPaint); 319 } 320 321 // Reset the opacity. 322 fPaint->setAlpha(255); 323 } 324