Refactor Nima code
There were two copies of a Nima "player" and this moves them out of samplecode/ and viewer/ to experimental/ where it is a bit more accessible (e.g. for WebAssembly). Bug: skia: Change-Id: I05419a352f0d13d16b462a374578107513eb1243 Reviewed-on: https://skia-review.googlesource.com/c/166441 Commit-Queue: Kevin Lubick <kjlubick@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
9877e8407b
commit
d969932474
3
BUILD.gn
3
BUILD.gn
@ -1689,6 +1689,7 @@ if (skia_enable_tools) {
|
||||
|
||||
# NIMA does not build on Windows clang
|
||||
if (!is_win || !is_clang) {
|
||||
sources += [ "experimental/nima/NimaActor.cpp" ]
|
||||
deps += [ "//third_party/Nima-Cpp" ]
|
||||
}
|
||||
|
||||
@ -2157,7 +2158,7 @@ if (skia_enable_tools) {
|
||||
]
|
||||
libs = []
|
||||
|
||||
include_dirs = []
|
||||
include_dirs = [ "experimental" ]
|
||||
deps = [
|
||||
":experimental_svg_model",
|
||||
":flags",
|
||||
|
323
experimental/nima/NimaActor.cpp
Normal file
323
experimental/nima/NimaActor.cpp
Normal file
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* 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 "NimaActor.h"
|
||||
|
||||
#include "SkData.h"
|
||||
#include "SkFilterQuality.h"
|
||||
#include "SkImage.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkString.h"
|
||||
#include "SkVertices.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
NimaActor::NimaActor(std::string nimaPath, std::string texturePath)
|
||||
: fTexture(nullptr)
|
||||
, fActorImages()
|
||||
, fPaint(nullptr)
|
||||
, fAnimationNames()
|
||||
, fAnimationInstance(nullptr) {
|
||||
// Load the NIMA data.
|
||||
INHERITED::load(nimaPath);
|
||||
|
||||
// Load the image asset.
|
||||
fTexture = SkImage::MakeFromEncoded(SkData::MakeFromFileName(texturePath.c_str()));
|
||||
|
||||
this->init();
|
||||
}
|
||||
|
||||
NimaActor::NimaActor(sk_sp<SkData> nimaBytes, sk_sp<SkData> textureBytes)
|
||||
: fTexture(nullptr)
|
||||
, fActorImages()
|
||||
, fPaint(nullptr)
|
||||
, fAnimationNames()
|
||||
, fAnimationInstance(nullptr) {
|
||||
// Load the NIMA data.
|
||||
INHERITED::load(const_cast<uint8_t*>(nimaBytes->bytes()), nimaBytes->size());
|
||||
|
||||
// Load the image asset.
|
||||
fTexture = SkImage::MakeFromEncoded(textureBytes);
|
||||
|
||||
this->init();
|
||||
}
|
||||
|
||||
void NimaActor::init() {
|
||||
// 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.get(), fPaint.get());
|
||||
}
|
||||
|
||||
// Sort the image nodes.
|
||||
std::sort(fActorImages.begin(), fActorImages.end(), [](auto a, auto b) {
|
||||
return a.drawOrder() < b.drawOrder();
|
||||
});
|
||||
|
||||
// Get the list of animations.
|
||||
fAnimationNames.reserve(m_AnimationsCount);
|
||||
for (uint32_t i = 0; i < m_AnimationsCount; i++) {
|
||||
fAnimationNames.push_back(m_Animations[i].name());
|
||||
}
|
||||
this->setAnimation(0);
|
||||
}
|
||||
|
||||
SkScalar NimaActor::duration() const {
|
||||
if (fAnimationInstance) {
|
||||
return fAnimationInstance->duration();
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void NimaActor::setAnimation(uint8_t index) {
|
||||
if (index < fAnimationNames.size()) {
|
||||
fAnimationIndex = index;
|
||||
fAnimationInstance = this->animationInstance(fAnimationNames[fAnimationIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
void NimaActor::setAnimation(std::string name) {
|
||||
for (size_t i = 0; i < fAnimationNames.size(); i++)
|
||||
{
|
||||
std::string aName = fAnimationNames[i];
|
||||
if (aName == name)
|
||||
{
|
||||
setAnimation(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NimaActor::render(SkCanvas* canvas, uint32_t renderFlags) {
|
||||
// Render the image nodes.
|
||||
for (auto& image : fActorImages) {
|
||||
image.render(canvas, renderFlags);
|
||||
}
|
||||
}
|
||||
|
||||
void NimaActor::seek(SkScalar t) {
|
||||
// Apply the animation.
|
||||
if (fAnimationInstance) {
|
||||
t = std::fmod(t, fAnimationInstance->max());
|
||||
fAnimationInstance->time(t);
|
||||
fAnimationInstance->apply(1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================================
|
||||
|
||||
NimaActorImage::NimaActorImage(nima::ActorImage* actorImage, SkImage* texture, SkPaint* paint)
|
||||
: fActorImage(actorImage)
|
||||
, fTexture(texture)
|
||||
, fPaint(paint)
|
||||
, fSkinned(false)
|
||||
, fPositions()
|
||||
, fTexs()
|
||||
, fBoneIdx()
|
||||
, fBoneWgt()
|
||||
, fIndices()
|
||||
, fBones()
|
||||
, fVertices(nullptr)
|
||||
, fRenderFlags(0) {
|
||||
// Update the vertices and bones.
|
||||
this->updateVertices(true);
|
||||
this->updateBones();
|
||||
}
|
||||
|
||||
void NimaActorImage::render(SkCanvas* canvas, uint32_t renderFlags) {
|
||||
bool dirty = renderFlags != fRenderFlags;
|
||||
fRenderFlags = renderFlags;
|
||||
|
||||
bool useImmediate = renderFlags & kImmediate_RenderFlag;
|
||||
bool useCache = renderFlags & kCache_RenderFlag;
|
||||
bool drawBounds = renderFlags & kBounds_RenderFlag;
|
||||
|
||||
// Don't use the cache if drawing in immediate mode.
|
||||
useCache &= !useImmediate;
|
||||
|
||||
if (fActorImage->doesAnimationVertexDeform() || dirty) {
|
||||
// These are vertices that transform beyond just bone transforms, so they must be
|
||||
// updated every frame.
|
||||
// If the render flags are dirty, reset the vertices object.
|
||||
this->updateVertices(!useCache);
|
||||
}
|
||||
|
||||
// Update the bones.
|
||||
this->updateBones();
|
||||
|
||||
// Deform the bones in immediate mode.
|
||||
sk_sp<SkVertices> vertices = fVertices;
|
||||
if (useImmediate) {
|
||||
vertices = fVertices->applyBones(fBones.data(), fBones.size());
|
||||
}
|
||||
|
||||
// Draw the vertices object.
|
||||
this->drawVerticesObject(vertices.get(), canvas, !useImmediate);
|
||||
|
||||
// Draw the bounds.
|
||||
if (drawBounds && fActorImage->renderOpacity() > 0.0f) {
|
||||
// Get the bounds.
|
||||
SkRect bounds = vertices->bounds();
|
||||
|
||||
// Approximate bounds if not using immediate transforms.
|
||||
if (!useImmediate) {
|
||||
const SkRect originalBounds = fBones[0].mapRect(vertices->bounds());
|
||||
bounds = originalBounds;
|
||||
for (size_t i = 1; i < fBones.size(); i++) {
|
||||
const SkVertices::Bone& matrix = fBones[i];
|
||||
bounds.join(matrix.mapRect(originalBounds));
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the bounds.
|
||||
SkPaint paint;
|
||||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
paint.setColor(0xFFFF0000);
|
||||
canvas->drawRect(bounds, paint);
|
||||
}
|
||||
}
|
||||
|
||||
void NimaActorImage::updateVertices(bool isVolatile) {
|
||||
// Update whether the image is skinned.
|
||||
fSkinned = fActorImage->connectedBoneCount() > 0;
|
||||
|
||||
// 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) {
|
||||
fPositions.clear();
|
||||
fTexs.clear();
|
||||
fBoneIdx.clear();
|
||||
fBoneWgt.clear();
|
||||
fIndices.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Split the vertex data.
|
||||
fPositions.resize(vertexCount);
|
||||
fTexs.resize(vertexCount);
|
||||
fIndices.resize(indexCount);
|
||||
if (fSkinned) {
|
||||
fBoneIdx.resize(vertexCount * 4);
|
||||
fBoneWgt.resize(vertexCount * 4);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// Set the data.
|
||||
fPositions[i].set(attrPosition[0], attrPosition[1]);
|
||||
fTexs[i].set(attrTex[0] * fTexture->width(), attrTex[1] * fTexture->height());
|
||||
if (fSkinned) {
|
||||
for (uint32_t k = 0; k < 4; k ++) {
|
||||
fBoneIdx[i][k] = static_cast<uint32_t>(attrBoneIdx[k]);
|
||||
fBoneWgt[i][k] = attrBoneWgt[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
memcpy(fIndices.data(), indexData, indexCount * sizeof(uint16_t));
|
||||
|
||||
// Update the vertices object.
|
||||
fVertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode,
|
||||
vertexCount,
|
||||
fPositions.data(),
|
||||
fTexs.data(),
|
||||
nullptr,
|
||||
fBoneIdx.data(),
|
||||
fBoneWgt.data(),
|
||||
fIndices.size(),
|
||||
fIndices.data(),
|
||||
isVolatile);
|
||||
}
|
||||
|
||||
void NimaActorImage::updateBones() {
|
||||
// NIMA matrices are a collection of 6 floats.
|
||||
constexpr int kNIMAMatrixSize = 6;
|
||||
|
||||
// Set up the matrices for the first time.
|
||||
if (fBones.size() == 0) {
|
||||
int numMatrices = 1;
|
||||
if (fSkinned) {
|
||||
numMatrices = fActorImage->boneInfluenceMatricesLength() / kNIMAMatrixSize;
|
||||
}
|
||||
|
||||
// Initialize all matrices to the identity matrix.
|
||||
fBones.assign(numMatrices, {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }});
|
||||
}
|
||||
|
||||
if (fSkinned) {
|
||||
// Update the matrices.
|
||||
float* matrixData = fActorImage->boneInfluenceMatrices();
|
||||
memcpy(fBones.data(), matrixData, fBones.size() * kNIMAMatrixSize * sizeof(float));
|
||||
}
|
||||
|
||||
// Set the zero matrix to be the world transform.
|
||||
memcpy(fBones.data(),
|
||||
fActorImage->worldTransform().values(),
|
||||
kNIMAMatrixSize * sizeof(float));
|
||||
}
|
||||
|
||||
void NimaActorImage::drawVerticesObject(SkVertices* vertices, SkCanvas* canvas, bool useBones) const {
|
||||
// Determine the blend mode.
|
||||
SkBlendMode blendMode;
|
||||
switch (fActorImage->blendMode()) {
|
||||
case nima::BlendMode::Off: {
|
||||
blendMode = SkBlendMode::kSrc;
|
||||
break;
|
||||
}
|
||||
case nima::BlendMode::Normal: {
|
||||
blendMode = SkBlendMode::kSrcOver;
|
||||
break;
|
||||
}
|
||||
case nima::BlendMode::Additive: {
|
||||
blendMode = SkBlendMode::kPlus;
|
||||
break;
|
||||
}
|
||||
case nima::BlendMode::Multiply: {
|
||||
blendMode = SkBlendMode::kMultiply;
|
||||
break;
|
||||
}
|
||||
case nima::BlendMode::Screen: {
|
||||
blendMode = SkBlendMode::kScreen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the opacity.
|
||||
fPaint->setAlpha(static_cast<U8CPU>(fActorImage->renderOpacity() * 255));
|
||||
|
||||
// Draw the vertices.
|
||||
if (useBones) {
|
||||
canvas->drawVertices(vertices, fBones.data(), fBones.size(), blendMode, *fPaint);
|
||||
} else {
|
||||
canvas->drawVertices(vertices, blendMode, *fPaint);
|
||||
}
|
||||
|
||||
// Reset the opacity.
|
||||
fPaint->setAlpha(255);
|
||||
}
|
133
experimental/nima/NimaActor.h
Normal file
133
experimental/nima/NimaActor.h
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef NimaActor_DEFINED
|
||||
#define NimaActor_DEFINED
|
||||
|
||||
#include <nima/Actor.hpp>
|
||||
#include <nima/ActorImage.hpp>
|
||||
#include <nima/Vec2D.hpp>
|
||||
|
||||
#include "SkCanvas.h"
|
||||
#include "SkData.h"
|
||||
#include "SkImage.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class NimaActor;
|
||||
class NimaActorImage;
|
||||
|
||||
enum RenderFlags {
|
||||
kImmediate_RenderFlag = 0x1,
|
||||
kCache_RenderFlag = 0x2,
|
||||
kBounds_RenderFlag = 0x4,
|
||||
};
|
||||
|
||||
/** \class NimaActor
|
||||
NimaActor acts as a breidge between Skia and a nima::Actor object.
|
||||
The Actor object essentially is a set of bones and textures.
|
||||
|
||||
NimaActor knows how to draw itself (the Actor) to an SkCanvas
|
||||
at various time stamps.
|
||||
|
||||
NimaActor is also aware of the different animation types the
|
||||
Actor has and coordinates switching between them. For example,
|
||||
an animation might have an "idle" and a "jump" animation it can
|
||||
switch between.
|
||||
*/
|
||||
class NimaActor : public nima::Actor {
|
||||
public:
|
||||
|
||||
NimaActor(std::string nimaPath, std::string texturePath);
|
||||
NimaActor(sk_sp<SkData> nimaBytes, sk_sp<SkData> textureBytes);
|
||||
|
||||
~NimaActor() = default;
|
||||
|
||||
/**
|
||||
* Render draws itself to the given canvas, at whatever
|
||||
* the current time position is (see seek).
|
||||
*/
|
||||
void render(SkCanvas* canvas, uint32_t renderFlags = 0);
|
||||
/**
|
||||
* Updates the animation state to be at time t.
|
||||
* This does not re-draw anything, another call to render() is required.
|
||||
*
|
||||
* @param t - number of second in (modulo total duration)
|
||||
*
|
||||
*/
|
||||
void seek(SkScalar t);
|
||||
|
||||
/**
|
||||
* Returns the duration of the current Actor's animation in seconds.
|
||||
*/
|
||||
SkScalar duration() const;
|
||||
|
||||
/**
|
||||
* Sets the animation type based on the index given. The default
|
||||
* animation index is 0. If index is invalid, nothing changes.
|
||||
*/
|
||||
void setAnimation(uint8_t index);
|
||||
|
||||
/**
|
||||
* Sets the animation type to be one that matches the provided
|
||||
* name. If the name does not match any of the existing animation
|
||||
* types, nothing changes.
|
||||
*/
|
||||
void setAnimation(std::string name);
|
||||
|
||||
/**
|
||||
* Returns all possible animation names. Use with setAnimation().
|
||||
*/
|
||||
const std::vector<std::string>& getAnimationNames() const {
|
||||
return fAnimationNames;
|
||||
}
|
||||
|
||||
private:
|
||||
void init();
|
||||
sk_sp<SkImage> fTexture;
|
||||
std::vector<NimaActorImage> fActorImages;
|
||||
std::unique_ptr<SkPaint> fPaint;
|
||||
std::vector<std::string> fAnimationNames;
|
||||
nima::ActorAnimationInstance* fAnimationInstance;
|
||||
uint8_t fAnimationIndex;
|
||||
|
||||
typedef nima::Actor INHERITED;
|
||||
};
|
||||
|
||||
// A wrapper class that handles rendering of ActorImages (renderable components NIMA Actors).
|
||||
class NimaActorImage {
|
||||
public:
|
||||
NimaActorImage(nima::ActorImage* actorImage, SkImage* texture, SkPaint* paint);
|
||||
~NimaActorImage() = default;
|
||||
|
||||
void render(SkCanvas* canvas, uint32_t renderFlags);
|
||||
|
||||
int drawOrder() const { return fActorImage->drawOrder(); }
|
||||
|
||||
private:
|
||||
nima::ActorImage* fActorImage;
|
||||
SkImage* fTexture;
|
||||
SkPaint* fPaint;
|
||||
|
||||
bool fSkinned;
|
||||
std::vector<SkPoint> fPositions;
|
||||
std::vector<SkPoint> fTexs;
|
||||
std::vector<SkVertices::BoneIndices> fBoneIdx;
|
||||
std::vector<SkVertices::BoneWeights> fBoneWgt;
|
||||
std::vector<uint16_t> fIndices;
|
||||
|
||||
std::vector<SkVertices::Bone> fBones;
|
||||
sk_sp<SkVertices> fVertices;
|
||||
|
||||
uint32_t fRenderFlags;
|
||||
|
||||
void updateVertices(bool isVolatile);
|
||||
void updateBones();
|
||||
void drawVerticesObject(SkVertices* vertices, SkCanvas* canvas, bool useBones) const;
|
||||
};
|
||||
|
||||
#endif
|
@ -67,8 +67,6 @@ samples_sources = [
|
||||
"$_samplecode/SampleMeasure.cpp",
|
||||
"$_samplecode/SampleMegaStroke.cpp",
|
||||
"$_samplecode/SampleNima.cpp",
|
||||
"$_samplecode/SampleNimaActor.cpp",
|
||||
"$_samplecode/SampleNimaActor.h",
|
||||
"$_samplecode/SamplePatch.cpp",
|
||||
"$_samplecode/SamplePath.cpp",
|
||||
"$_samplecode/SamplePathText.cpp",
|
||||
@ -109,9 +107,5 @@ samples_sources = [
|
||||
]
|
||||
|
||||
if (is_win && is_clang) {
|
||||
samples_sources -= [
|
||||
"$_samplecode/SampleNimaActor.cpp",
|
||||
"$_samplecode/SampleNimaActor.h",
|
||||
"$_samplecode/SampleNima.cpp",
|
||||
]
|
||||
samples_sources -= [ "$_samplecode/SampleNima.cpp" ]
|
||||
}
|
||||
|
@ -6,8 +6,11 @@
|
||||
*/
|
||||
|
||||
#include "Sample.h"
|
||||
#include "SampleNimaActor.h"
|
||||
|
||||
#include "Resources.h"
|
||||
#include "SkAnimTimer.h"
|
||||
#include "nima/NimaActor.h"
|
||||
|
||||
#include <nima/Animation/ActorAnimationInstance.hpp>
|
||||
#include <cmath>
|
||||
|
||||
@ -16,8 +19,7 @@ using namespace nima;
|
||||
class NimaView : public Sample {
|
||||
public:
|
||||
NimaView()
|
||||
: fActor(nullptr)
|
||||
, fAnimation(nullptr) {
|
||||
: fActor(nullptr) {
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -31,16 +33,19 @@ protected:
|
||||
|
||||
void onOnceBeforeDraw() override {
|
||||
// Create the actor.
|
||||
fActor = std::make_unique<SampleActor>("Robot");
|
||||
std::string nimaPath(GetResourcePath("nima/Robot.nima").c_str());
|
||||
std::string texturePath(GetResourcePath("nima/Robot.png").c_str());
|
||||
|
||||
// Get the animation.
|
||||
fAnimation = fActor->animationInstance("attack");
|
||||
fActor = std::make_unique<NimaActor>(nimaPath, texturePath);
|
||||
|
||||
// Also available: dance, jump, idle
|
||||
fActor->setAnimation("attack");
|
||||
}
|
||||
|
||||
void onDrawContent(SkCanvas* canvas) override {
|
||||
canvas->save();
|
||||
|
||||
canvas->translate(500, 500);
|
||||
canvas->translate(500, 700);
|
||||
canvas->scale(1, -1);
|
||||
|
||||
// Render the actor.
|
||||
@ -50,18 +55,15 @@ protected:
|
||||
}
|
||||
|
||||
bool onAnimate(const SkAnimTimer& timer) override {
|
||||
// Apply the animation.
|
||||
if (fAnimation) {
|
||||
float time = std::fmod(timer.secs(), fAnimation->max());
|
||||
fAnimation->time(time);
|
||||
fAnimation->apply(1.0f);
|
||||
if (fActor) {
|
||||
float time = std::fmod(timer.secs(), fActor->duration());
|
||||
fActor->seek(time);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<SampleActor> fActor;
|
||||
ActorAnimationInstance* fAnimation;
|
||||
std::unique_ptr<NimaActor> fActor;
|
||||
|
||||
typedef Sample INHERITED;
|
||||
};
|
||||
|
@ -1,185 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SampleNimaActor_DEFINED
|
||||
#define SampleNimaActor_DEFINED
|
||||
|
||||
#include <nima/Actor.hpp>
|
||||
#include <nima/ActorImage.hpp>
|
||||
#include <nima/Vec2D.hpp>
|
||||
|
||||
#include "SkCanvas.h"
|
||||
#include "SkImage.h"
|
||||
|
||||
class SampleActor;
|
||||
class SampleActorImage;
|
||||
|
||||
class SampleActor : public nima::Actor {
|
||||
public:
|
||||
SampleActor(std::string baseName);
|
||||
~SampleActor();
|
||||
|
||||
void render(SkCanvas* canvas) const;
|
||||
|
||||
private:
|
||||
sk_sp<SkImage> fTexture;
|
||||
std::vector<SampleActorImage> fActorImages;
|
||||
std::unique_ptr<SkPaint> fPaint;
|
||||
|
||||
typedef nima::Actor INHERITED;
|
||||
};
|
||||
|
||||
class SampleActorImage {
|
||||
public:
|
||||
SampleActorImage(nima::ActorImage* actorImage, sk_sp<SkImage> texture, SkPaint* paint);
|
||||
~SampleActorImage();
|
||||
|
||||
void render(const SampleActor* actor, SkCanvas* canvas) const;
|
||||
|
||||
int drawOrder() const { return fActorImage->drawOrder(); }
|
||||
|
||||
private:
|
||||
nima::Vec2D deform(const nima::Vec2D& position, float* boneIdx, float* boneWgt) const;
|
||||
|
||||
private:
|
||||
nima::ActorImage* fActorImage;
|
||||
sk_sp<SkImage> fTexture;
|
||||
SkPaint* fPaint;
|
||||
};
|
||||
|
||||
#endif
|
@ -7,10 +7,11 @@
|
||||
|
||||
#include "NIMASlide.h"
|
||||
|
||||
#include "Resources.h"
|
||||
#include "SkAnimTimer.h"
|
||||
#include "SkOSPath.h"
|
||||
#include "Resources.h"
|
||||
#include "imgui.h"
|
||||
#include "nima/NimaActor.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
@ -27,306 +28,15 @@ static bool vector_getter(void* v, int index, const char** out) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// A wrapper class that handles rendering of ActorImages (renderable components NIMA Actors).
|
||||
class NIMAActorImage {
|
||||
public:
|
||||
NIMAActorImage(ActorImage* actorImage, SkImage* texture, SkPaint* paint)
|
||||
: fActorImage(actorImage)
|
||||
, fTexture(texture)
|
||||
, fPaint(paint)
|
||||
, fSkinned(false)
|
||||
, fPositions()
|
||||
, fTexs()
|
||||
, fBoneIdx()
|
||||
, fBoneWgt()
|
||||
, fIndices()
|
||||
, fBones()
|
||||
, fVertices(nullptr)
|
||||
, fRenderFlags(0) {
|
||||
// Update the vertices and bones.
|
||||
this->updateVertices(true);
|
||||
this->updateBones();
|
||||
}
|
||||
|
||||
void render(SkCanvas* canvas, uint32_t renderFlags) {
|
||||
bool dirty = renderFlags != fRenderFlags;
|
||||
fRenderFlags = renderFlags;
|
||||
|
||||
bool useImmediate = renderFlags & kImmediate_RenderFlag;
|
||||
bool useCache = renderFlags & kCache_RenderFlag;
|
||||
bool drawBounds = renderFlags & kBounds_RenderFlag;
|
||||
|
||||
// Don't use the cache if drawing in immediate mode.
|
||||
useCache &= !useImmediate;
|
||||
|
||||
if (fActorImage->doesAnimationVertexDeform() || dirty) {
|
||||
// These are vertices that transform beyond just bone transforms, so they must be
|
||||
// updated every frame.
|
||||
// If the render flags are dirty, reset the vertices object.
|
||||
this->updateVertices(!useCache);
|
||||
}
|
||||
|
||||
// Update the bones.
|
||||
this->updateBones();
|
||||
|
||||
// Deform the bones in immediate mode.
|
||||
sk_sp<SkVertices> vertices = fVertices;
|
||||
if (useImmediate) {
|
||||
vertices = fVertices->applyBones(fBones.data(), fBones.size());
|
||||
}
|
||||
|
||||
// Draw the vertices object.
|
||||
this->drawVerticesObject(vertices.get(), canvas, !useImmediate);
|
||||
|
||||
// Draw the bounds.
|
||||
if (drawBounds && fActorImage->renderOpacity() > 0.0f) {
|
||||
// Get the bounds.
|
||||
SkRect bounds = vertices->bounds();
|
||||
|
||||
// Approximate bounds if not using immediate transforms.
|
||||
if (!useImmediate) {
|
||||
const SkRect originalBounds = fBones[0].mapRect(vertices->bounds());
|
||||
bounds = originalBounds;
|
||||
for (size_t i = 1; i < fBones.size(); i++) {
|
||||
const SkVertices::Bone& matrix = fBones[i];
|
||||
bounds.join(matrix.mapRect(originalBounds));
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the bounds.
|
||||
SkPaint paint;
|
||||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
paint.setColor(0xFFFF0000);
|
||||
canvas->drawRect(bounds, paint);
|
||||
}
|
||||
}
|
||||
|
||||
int drawOrder() const { return fActorImage->drawOrder(); }
|
||||
|
||||
private:
|
||||
void updateVertices(bool isVolatile) {
|
||||
// Update whether the image is skinned.
|
||||
fSkinned = fActorImage->connectedBoneCount() > 0;
|
||||
|
||||
// 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) {
|
||||
fPositions.clear();
|
||||
fTexs.clear();
|
||||
fBoneIdx.clear();
|
||||
fBoneWgt.clear();
|
||||
fIndices.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Split the vertex data.
|
||||
fPositions.resize(vertexCount);
|
||||
fTexs.resize(vertexCount);
|
||||
fIndices.resize(indexCount);
|
||||
if (fSkinned) {
|
||||
fBoneIdx.resize(vertexCount * 4);
|
||||
fBoneWgt.resize(vertexCount * 4);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// Set the data.
|
||||
fPositions[i].set(attrPosition[0], attrPosition[1]);
|
||||
fTexs[i].set(attrTex[0] * fTexture->width(), attrTex[1] * fTexture->height());
|
||||
if (fSkinned) {
|
||||
for (uint32_t k = 0; k < 4; k ++) {
|
||||
fBoneIdx[i][k] = static_cast<uint32_t>(attrBoneIdx[k]);
|
||||
fBoneWgt[i][k] = attrBoneWgt[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
memcpy(fIndices.data(), indexData, indexCount * sizeof(uint16_t));
|
||||
|
||||
// Update the vertices object.
|
||||
fVertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode,
|
||||
vertexCount,
|
||||
fPositions.data(),
|
||||
fTexs.data(),
|
||||
nullptr,
|
||||
fBoneIdx.data(),
|
||||
fBoneWgt.data(),
|
||||
fIndices.size(),
|
||||
fIndices.data(),
|
||||
isVolatile);
|
||||
}
|
||||
|
||||
void updateBones() {
|
||||
// NIMA matrices are a collection of 6 floats.
|
||||
constexpr int kNIMAMatrixSize = 6;
|
||||
|
||||
// Set up the matrices for the first time.
|
||||
if (fBones.size() == 0) {
|
||||
int numMatrices = 1;
|
||||
if (fSkinned) {
|
||||
numMatrices = fActorImage->boneInfluenceMatricesLength() / kNIMAMatrixSize;
|
||||
}
|
||||
|
||||
// Initialize all matrices to the identity matrix.
|
||||
fBones.assign(numMatrices, {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }});
|
||||
}
|
||||
|
||||
if (fSkinned) {
|
||||
// Update the matrices.
|
||||
float* matrixData = fActorImage->boneInfluenceMatrices();
|
||||
memcpy(fBones.data(), matrixData, fBones.size() * kNIMAMatrixSize * sizeof(float));
|
||||
}
|
||||
|
||||
// Set the zero matrix to be the world transform.
|
||||
memcpy(fBones.data(),
|
||||
fActorImage->worldTransform().values(),
|
||||
kNIMAMatrixSize * sizeof(float));
|
||||
}
|
||||
|
||||
void drawVerticesObject(SkVertices* vertices, SkCanvas* canvas, bool useBones) const {
|
||||
// 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.
|
||||
if (useBones) {
|
||||
canvas->drawVertices(vertices, fBones.data(), fBones.size(), blendMode, *fPaint);
|
||||
} else {
|
||||
canvas->drawVertices(vertices, blendMode, *fPaint);
|
||||
}
|
||||
|
||||
// Reset the opacity.
|
||||
fPaint->setAlpha(255);
|
||||
}
|
||||
|
||||
private:
|
||||
ActorImage* fActorImage;
|
||||
SkImage* fTexture;
|
||||
SkPaint* fPaint;
|
||||
|
||||
bool fSkinned;
|
||||
std::vector<SkPoint> fPositions;
|
||||
std::vector<SkPoint> fTexs;
|
||||
std::vector<SkVertices::BoneIndices> fBoneIdx;
|
||||
std::vector<SkVertices::BoneWeights> fBoneWgt;
|
||||
std::vector<uint16_t> fIndices;
|
||||
|
||||
std::vector<SkVertices::Bone> fBones;
|
||||
sk_sp<SkVertices> fVertices;
|
||||
|
||||
uint32_t fRenderFlags;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Represents an Actor, or an animated character, in NIMA.
|
||||
class NIMAActor : public Actor {
|
||||
public:
|
||||
NIMAActor(const std::string& basePath)
|
||||
: fTexture(nullptr)
|
||||
, fActorImages()
|
||||
, fPaint()
|
||||
, fAnimations() {
|
||||
// Load the NIMA data.
|
||||
std::string nimaPath((basePath + ".nima").c_str());
|
||||
INHERITED::load(nimaPath);
|
||||
|
||||
// Load the image asset.
|
||||
sk_sp<SkData> imageData = SkData::MakeFromFileName((basePath + ".png").c_str());
|
||||
fTexture = SkImage::MakeFromEncoded(imageData);
|
||||
|
||||
// Create the paint.
|
||||
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.get(), &fPaint);
|
||||
}
|
||||
|
||||
// Sort the image nodes.
|
||||
std::sort(fActorImages.begin(), fActorImages.end(), [](auto a, auto b) {
|
||||
return a.drawOrder() < b.drawOrder();
|
||||
});
|
||||
|
||||
// Get the list of animations.
|
||||
fAnimations.reserve(m_AnimationsCount);
|
||||
for (uint32_t i = 0; i < m_AnimationsCount; i ++) {
|
||||
fAnimations.push_back(m_Animations[i].name());
|
||||
}
|
||||
}
|
||||
|
||||
void render(SkCanvas* canvas, uint32_t renderFlags) {
|
||||
// Render the image nodes.
|
||||
for (auto& image : fActorImages) {
|
||||
image.render(canvas, renderFlags);
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<std::string>& getAnimations() const {
|
||||
return fAnimations;
|
||||
}
|
||||
|
||||
private:
|
||||
sk_sp<SkImage> fTexture;
|
||||
std::vector<NIMAActorImage> fActorImages;
|
||||
SkPaint fPaint;
|
||||
std::vector<std::string> fAnimations;
|
||||
|
||||
typedef Actor INHERITED;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NIMASlide::NIMASlide(const SkString& name, const SkString& path)
|
||||
: fBasePath()
|
||||
, fActor(nullptr)
|
||||
, fAnimationIndex(0)
|
||||
, fPlaying(true)
|
||||
, fTime(0.0f)
|
||||
, fRenderFlags(0)
|
||||
, fAnimation(nullptr)
|
||||
, fAnimationIndex(0) {
|
||||
, fRenderFlags(0) {
|
||||
fName = name;
|
||||
|
||||
// Get the path components.
|
||||
@ -356,6 +66,7 @@ void NIMASlide::draw(SkCanvas* canvas) {
|
||||
canvas->scale(0.5, -0.5);
|
||||
|
||||
// Render the actor.
|
||||
fActor->setAnimation(fAnimationIndex);
|
||||
fActor->render(canvas, fRenderFlags);
|
||||
|
||||
canvas->restore();
|
||||
@ -374,18 +85,14 @@ void NIMASlide::load(SkScalar winWidth, SkScalar winHeight) {
|
||||
|
||||
void NIMASlide::unload() {
|
||||
// Discard resources.
|
||||
fAnimation = nullptr;
|
||||
fActor.reset(nullptr);
|
||||
}
|
||||
|
||||
bool NIMASlide::animate(const SkAnimTimer& timer) {
|
||||
// Apply the animation.
|
||||
if (fAnimation) {
|
||||
if (fPlaying) {
|
||||
fTime = std::fmod(timer.secs(), fAnimation->max());
|
||||
}
|
||||
fAnimation->time(fTime);
|
||||
fAnimation->apply(1.0f);
|
||||
if (fActor) {
|
||||
float time = std::fmod(timer.secs(), fActor->duration());
|
||||
fActor->seek(time);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -400,10 +107,10 @@ bool NIMASlide::onMouse(SkScalar x, SkScalar y, Window::InputState state, uint32
|
||||
|
||||
void NIMASlide::resetActor() {
|
||||
// Create the actor.
|
||||
fActor = std::make_unique<NIMAActor>(fBasePath);
|
||||
std::string nimaPath = fBasePath + ".nima";
|
||||
std::string texturePath = fBasePath + ".png";
|
||||
|
||||
// Get the animation.
|
||||
fAnimation = fActor->animationInstance(fActor->getAnimations()[fAnimationIndex]);
|
||||
fActor = std::make_unique<NimaActor>(nimaPath, texturePath);
|
||||
}
|
||||
|
||||
void NIMASlide::renderGUI() {
|
||||
@ -411,7 +118,7 @@ void NIMASlide::renderGUI() {
|
||||
ImGui::Begin("NIMA");
|
||||
|
||||
// List of animations.
|
||||
auto animations = const_cast<std::vector<std::string>&>(fActor->getAnimations());
|
||||
auto animations = const_cast<std::vector<std::string>&>(fActor->getAnimationNames());
|
||||
ImGui::PushItemWidth(-1);
|
||||
if (ImGui::ListBox("Animations",
|
||||
&fAnimationIndex,
|
||||
@ -434,7 +141,7 @@ void NIMASlide::renderGUI() {
|
||||
|
||||
// Time slider.
|
||||
ImGui::PushItemWidth(-1);
|
||||
ImGui::SliderFloat("Time", &fTime, 0.0f, fAnimation->max(), "Time: %.3f");
|
||||
ImGui::SliderFloat("Time", &fTime, 0.0f, fActor->duration(), "Time: %.3f");
|
||||
|
||||
// Backend control.
|
||||
int useImmediate = SkToBool(fRenderFlags & kImmediate_RenderFlag);
|
||||
|
@ -12,19 +12,7 @@
|
||||
|
||||
#include "SkCanvas.h"
|
||||
#include "SkVertices.h"
|
||||
#include <nima/Actor.hpp>
|
||||
#include <nima/ActorImage.hpp>
|
||||
#include <nima/Animation/ActorAnimationInstance.hpp>
|
||||
#include <nima/Vec2D.hpp>
|
||||
|
||||
class NIMAActor;
|
||||
class NIMAActorImage;
|
||||
|
||||
enum RenderFlags {
|
||||
kImmediate_RenderFlag = 0x1,
|
||||
kCache_RenderFlag = 0x2,
|
||||
kBounds_RenderFlag = 0x4,
|
||||
};
|
||||
#include "nima/NimaActor.h"
|
||||
|
||||
class NIMASlide : public Slide {
|
||||
public:
|
||||
@ -49,14 +37,12 @@ private:
|
||||
|
||||
private:
|
||||
std::string fBasePath;
|
||||
std::unique_ptr<NIMAActor> fActor;
|
||||
std::unique_ptr<NimaActor> fActor;
|
||||
int fAnimationIndex;
|
||||
|
||||
bool fPlaying;
|
||||
float fTime;
|
||||
uint32_t fRenderFlags;
|
||||
|
||||
nima::ActorAnimationInstance* fAnimation;
|
||||
int fAnimationIndex;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user