c5c3df6643
Bug: skia: Change-Id: I305ca837d5ed35df4b519e7283201f0a0f87b1c3 Reviewed-on: https://skia-review.googlesource.com/136636 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: Ruiqi Mao <ruiqimao@google.com>
186 lines
5.8 KiB
C++
186 lines
5.8 KiB
C++
/*
|
|
* 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 <algorithm>
|
|
|
|
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<SkPaint>();
|
|
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<SkImage> 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<SkPoint> positions(vertexCount);
|
|
std::vector<SkPoint> 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<SkVertices> 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<U8CPU>(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<int>(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);
|
|
}
|