Home | History | Annotate | Download | only in nima
      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