/* * Copyright 2018 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SampleNimaActor.h" #include "SkString.h" #include "SkVertices.h" #include "SkPaint.h" #include "SkFilterQuality.h" #include "Resources.h" #include using namespace nima; SampleActor::SampleActor(std::string baseName) : fTexture(nullptr) , fActorImages() , fPaint(nullptr) { // Load the NIMA data. SkString nimaSkPath = GetResourcePath(("nima/" + baseName + ".nima").c_str()); std::string nimaPath(nimaSkPath.c_str()); INHERITED::load(nimaPath); // Load the image asset. fTexture = GetResourceAsImage(("nima/" + baseName + ".png").c_str()); // Create the paint. fPaint = std::make_unique(); fPaint->setShader(fTexture->makeShader(nullptr)); fPaint->setFilterQuality(SkFilterQuality::kLow_SkFilterQuality); // Load the image nodes. fActorImages.reserve(m_ImageNodeCount); for (uint32_t i = 0; i < m_ImageNodeCount; i ++) { fActorImages.emplace_back(m_ImageNodes[i], fTexture, fPaint.get()); } // Sort the image nodes. std::sort(fActorImages.begin(), fActorImages.end(), [](auto a, auto b) { return a.drawOrder() < b.drawOrder(); }); } SampleActor::~SampleActor() { } void SampleActor::render(SkCanvas* canvas) const { // Render the image nodes. for (auto image : fActorImages) { image.render(this, canvas); } } SampleActorImage::SampleActorImage(ActorImage* actorImage, sk_sp texture, SkPaint* paint) : fActorImage(actorImage) , fTexture(texture) , fPaint(paint) { } SampleActorImage::~SampleActorImage() { } void SampleActorImage::render(const SampleActor* actor, SkCanvas* canvas) const { // Retrieve data from the image. uint32_t vertexCount = fActorImage->vertexCount(); uint32_t vertexStride = fActorImage->vertexStride(); float* vertexData = fActorImage->vertices(); uint32_t indexCount = fActorImage->triangleCount() * 3; uint16_t* indexData = fActorImage->triangles(); // Don't render if not visible. if (!vertexCount || fActorImage->textureIndex() < 0) { return; } // Split the vertex data. std::vector positions(vertexCount); std::vector texs(vertexCount); for (uint32_t i = 0; i < vertexCount; i ++) { uint32_t j = i * vertexStride; // Get the attributes. float* attrPosition = vertexData + j; float* attrTex = vertexData + j + 2; float* attrBoneIdx = vertexData + j + 4; float* attrBoneWgt = vertexData + j + 8; // Get deformed positions if necessary. if (fActorImage->doesAnimationVertexDeform()) { attrPosition = fActorImage->animationDeformedVertices() + i * 2; } // Deform the position. Vec2D position(attrPosition[0], attrPosition[1]); if (fActorImage->connectedBoneCount() > 0) { position = deform(position, attrBoneIdx, attrBoneWgt); } else { position = deform(position, nullptr, nullptr); } // Set the data. positions[i].set(position[0], position[1]); texs[i].set(attrTex[0] * fTexture->width(), attrTex[1] * fTexture->height()); } // Create vertices. sk_sp vertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, vertexCount, positions.data(), texs.data(), nullptr, indexCount, indexData); // Determine the blend mode. SkBlendMode blendMode; switch (fActorImage->blendMode()) { case BlendMode::Off: { blendMode = SkBlendMode::kSrc; break; } case BlendMode::Normal: { blendMode = SkBlendMode::kSrcOver; break; } case BlendMode::Additive: { blendMode = SkBlendMode::kPlus; break; } case BlendMode::Multiply: { blendMode = SkBlendMode::kMultiply; break; } case BlendMode::Screen: { blendMode = SkBlendMode::kScreen; break; } } // Set the opacity. fPaint->setAlpha(static_cast(fActorImage->renderOpacity() * 255)); // Draw the vertices. canvas->drawVertices(vertices, blendMode, *fPaint); // Reset the opacity. fPaint->setAlpha(255); } Vec2D SampleActorImage::deform(const Vec2D& position, float* boneIdx, float* boneWgt) const { float px = position[0], py = position[1]; float px2 = px, py2 = py; float influence[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; // Apply the world transform. Mat2D worldTransform = fActorImage->worldTransform(); px2 = worldTransform[0] * px + worldTransform[2] * py + worldTransform[4]; py2 = worldTransform[1] * px + worldTransform[3] * py + worldTransform[5]; // Apply deformations based on bone offsets. if (boneIdx && boneWgt) { float* matrices = fActorImage->boneInfluenceMatrices(); for (uint32_t i = 0; i < 4; i ++) { int index = static_cast(boneIdx[i]); float weight = boneWgt[i]; for (int j = 0; j < 6; j ++) { influence[j] += matrices[index * 6 + j] * weight; } } px = influence[0] * px2 + influence[2] * py2 + influence[4]; py = influence[1] * px2 + influence[3] * py2 + influence[5]; } else { px = px2; py = py2; } // Return the transformed position. return Vec2D(px, py); }