added NIMA sample to showcase animations

improved third_party template to include headers as system headers for non-Windows machines

Bug: skia:
Change-Id: Id2fa74fc31b49f9b07cc83e7f60477c7ab4f8d83
Reviewed-on: https://skia-review.googlesource.com/135450
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2018-06-19 16:05:09 -04:00 committed by Skia Commit-Bot
parent 644341af03
commit c069a57301
10 changed files with 450 additions and 10 deletions

View File

@ -1547,6 +1547,7 @@ if (skia_enable_tools) {
":xml",
"modules/sksg:samples",
"modules/skshaper",
"//third_party/Nima-Cpp",
]
if (skia_use_lua) {
@ -1576,6 +1577,7 @@ if (skia_enable_tools) {
":tool_utils",
"modules/skottie",
"modules/sksg",
"//third_party/Nima-Cpp",
"//third_party/jsoncpp",
"//third_party/libpng",
]
@ -1999,6 +2001,7 @@ if (skia_enable_tools) {
":views",
"modules/skottie",
"modules/sksg",
"//third_party/Nima-Cpp",
"//third_party/imgui",
]
}

2
DEPS
View File

@ -28,6 +28,8 @@ deps = {
"third_party/externals/swiftshader" : "https://swiftshader.googlesource.com/SwiftShader@1fa20678010892b3b531e7449f25079868dfba45",
#"third_party/externals/v8" : "https://chromium.googlesource.com/v8/v8.git@5f1ae66d5634e43563b2d25ea652dfb94c31a3b4",
"third_party/externals/zlib" : "https://chromium.googlesource.com/chromium/src/third_party/zlib@e7afdfe128e01ca480a28f757b571957befdd962",
"third_party/externals/Nima-Cpp" : "https://github.com/2d-inc/Nima-Cpp.git@4bd02269d7d1d2e650950411325eafa15defb084",
"third_party/externals/Nima-Math-Cpp" : "https://github.com/2d-inc/Nima-Math-Cpp.git@e0c12772093fa8860f55358274515b86885f0108",
}
recursedeps = [ "common" ]

View File

@ -8,6 +8,8 @@ _samplecode = get_path_info("../samplecode", "abspath")
samples_sources = [
"$_samplecode/ClockFaceView.cpp",
"$_samplecode/Nima.cpp",
"$_samplecode/Nima.h",
"$_samplecode/PerlinPatch.cpp",
"$_samplecode/Sample2PtRadial.cpp",
"$_samplecode/SampleAAClip.cpp",
@ -64,6 +66,7 @@ samples_sources = [
"$_samplecode/SampleManyRects.cpp",
"$_samplecode/SampleMeasure.cpp",
"$_samplecode/SampleMegaStroke.cpp",
"$_samplecode/SampleNima.cpp",
"$_samplecode/SamplePatch.cpp",
"$_samplecode/SamplePath.cpp",
"$_samplecode/SamplePathText.cpp",
@ -103,3 +106,11 @@ samples_sources = [
"$_samplecode/SampleXfermodesBlur.cpp",
"$_samplecode/vertexdump.cpp",
]
if (is_win && is_clang) {
samples_sources -= [
"$_samplecode/Nima.cpp",
"$_samplecode/Nima.h",
"$_samplecode/SampleNima.cpp",
]
}

BIN
resources/nima/Robot.nima Normal file

Binary file not shown.

BIN
resources/nima/Robot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

180
samplecode/Nima.cpp Normal file
View File

@ -0,0 +1,180 @@
/*
* 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 "Nima.h"
#include "SkString.h"
#include "SkVertices.h"
#include "SkPaint.h"
#include "Resources.h"
#include <algorithm>
#include <iostream>
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));
// 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;
// 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);
}

54
samplecode/Nima.h Normal file
View File

@ -0,0 +1,54 @@
/*
* 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 Nima_DEFINED
#define Nima_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

72
samplecode/SampleNima.cpp Normal file
View File

@ -0,0 +1,72 @@
/*
* 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 "SampleCode.h"
#include "Nima.h"
#include "SkAnimTimer.h"
#include "SkView.h"
#include <nima/Animation/ActorAnimation.hpp>
#include <cmath>
using namespace nima;
class NimaView : public SampleView {
public:
NimaView()
: fActor(nullptr) {
}
protected:
// overrides from SkEventSink
virtual bool onQuery(SkEvent* evt) override {
if (SampleCode::TitleQ(*evt)) {
SampleCode::TitleR(evt, "Nima");
return true;
}
return this->INHERITED::onQuery(evt);
}
void onOnceBeforeDraw() override {
// Create the actor.
fActor = std::make_unique<SampleActor>("Robot");
// Get the animation.
fAnimation = fActor->animation("jump");
}
void onDrawContent(SkCanvas* canvas) override {
canvas->save();
canvas->translate(500, 500);
canvas->scale(1, -1);
// Render the actor.
fActor->render(canvas);
canvas->restore();
}
bool onAnimate(const SkAnimTimer& timer) override {
// Apply the animation.
if (fAnimation) {
float time = std::fmod(timer.secs(), fAnimation->duration());
fAnimation->apply(time, fActor.get(), 1.0f);
}
return true;
}
private:
std::unique_ptr<SampleActor> fActor;
ActorAnimation* fAnimation = nullptr;
typedef SampleView INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
static SkView* MyFactory() { return new NimaView; }
static SkViewRegister reg(MyFactory);

101
third_party/Nima-Cpp/BUILD.gn vendored Normal file
View File

@ -0,0 +1,101 @@
# Copyright 2018 Google Inc.
#
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("../third_party.gni")
copy("copy-nima-cpp") {
sources = [
"../externals/Nima-Cpp/Source",
]
outputs = [
"$target_gen_dir/Nima-Cpp/nima",
]
}
copy("copy-nima-math-cpp") {
sources = [
"../externals/Nima-Math-Cpp/Source",
]
outputs = [
"$target_gen_dir/Nima-Math-Cpp/nima",
]
}
third_party("Nima-Cpp") {
deps = [
":copy-nima-cpp",
":copy-nima-math-cpp",
]
public_include_dirs = [
"$target_gen_dir/Nima-Cpp",
"$target_gen_dir/Nima-Math-Cpp",
]
configs -= [
"//gn:no_exceptions",
"//gn:no_rtti",
]
sources = [
"../externals/Nima-Cpp/Source/Actor.cpp",
"../externals/Nima-Cpp/Source/ActorBone.cpp",
"../externals/Nima-Cpp/Source/ActorCollider.cpp",
"../externals/Nima-Cpp/Source/ActorComponent.cpp",
"../externals/Nima-Cpp/Source/ActorEvent.cpp",
"../externals/Nima-Cpp/Source/ActorIKTarget.cpp",
"../externals/Nima-Cpp/Source/ActorImage.cpp",
"../externals/Nima-Cpp/Source/ActorInstance.cpp",
"../externals/Nima-Cpp/Source/ActorNode.cpp",
"../externals/Nima-Cpp/Source/ActorNodeSolo.cpp",
"../externals/Nima-Cpp/Source/ActorRenderNode.cpp",
"../externals/Nima-Cpp/Source/ActorRootBone.cpp",
"../externals/Nima-Cpp/Source/ActorStaticMesh.cpp",
"../externals/Nima-Cpp/Source/Animation/ActorAnimation.cpp",
"../externals/Nima-Cpp/Source/Animation/ActorAnimationInstance.cpp",
"../externals/Nima-Cpp/Source/Animation/ComponentAnimation.cpp",
"../externals/Nima-Cpp/Source/Animation/Interpolators/CubicSolver.cpp",
"../externals/Nima-Cpp/Source/Animation/Interpolators/ValueTimeCurveInterpolator.cpp",
"../externals/Nima-Cpp/Source/Animation/KeyFrames/KeyFrame.cpp",
"../externals/Nima-Cpp/Source/Animation/KeyFrames/KeyFrameActiveChild.cpp",
"../externals/Nima-Cpp/Source/Animation/KeyFrames/KeyFrameCustomProperty.cpp",
"../externals/Nima-Cpp/Source/Animation/KeyFrames/KeyFrameDrawOrder.cpp",
"../externals/Nima-Cpp/Source/Animation/KeyFrames/KeyFrameIKStrength.cpp",
"../externals/Nima-Cpp/Source/Animation/KeyFrames/KeyFrameIsCollisionEnabled.cpp",
"../externals/Nima-Cpp/Source/Animation/KeyFrames/KeyFrameLength.cpp",
"../externals/Nima-Cpp/Source/Animation/KeyFrames/KeyFrameNumeric.cpp",
"../externals/Nima-Cpp/Source/Animation/KeyFrames/KeyFrameOpacity.cpp",
"../externals/Nima-Cpp/Source/Animation/KeyFrames/KeyFramePosX.cpp",
"../externals/Nima-Cpp/Source/Animation/KeyFrames/KeyFramePosY.cpp",
"../externals/Nima-Cpp/Source/Animation/KeyFrames/KeyFrameRotation.cpp",
"../externals/Nima-Cpp/Source/Animation/KeyFrames/KeyFrameScaleX.cpp",
"../externals/Nima-Cpp/Source/Animation/KeyFrames/KeyFrameScaleY.cpp",
"../externals/Nima-Cpp/Source/Animation/KeyFrames/KeyFrameSequence.cpp",
"../externals/Nima-Cpp/Source/Animation/KeyFrames/KeyFrameTrigger.cpp",
"../externals/Nima-Cpp/Source/Animation/KeyFrames/KeyFrameVertexDeform.cpp",
"../externals/Nima-Cpp/Source/Animation/KeyFrames/KeyFrameWithInterpolation.cpp",
"../externals/Nima-Cpp/Source/Animation/PropertyAnimation.cpp",
"../externals/Nima-Cpp/Source/BinaryReader.cpp",
"../externals/Nima-Cpp/Source/BlockReader.cpp",
"../externals/Nima-Cpp/Source/CustomProperty.cpp",
"../externals/Nima-Cpp/Source/NestedActorAsset.cpp",
"../externals/Nima-Cpp/Source/NestedActorNode.cpp",
"../externals/Nima-Math-Cpp/Source/Mat2D.cpp",
"../externals/Nima-Math-Cpp/Source/Vec2D.cpp",
]
testonly = true
cflags_cc = []
if (is_win) {
defines = [ "_USE_MATH_DEFINES" ]
cflags_cc += [
"/FI",
"algorithm",
]
}
enabled = !is_win || !is_clang
}

View File

@ -4,21 +4,38 @@
# found in the LICENSE file.
template("third_party") {
enabled = !defined(invoker.enabled) || invoker.enabled
config(target_name + "_public") {
if (defined(invoker.public_defines)) {
defines = invoker.public_defines
if (enabled) {
cflags = []
if (defined(invoker.public_defines)) {
defines = invoker.public_defines
}
if (is_win) {
include_dirs = invoker.public_include_dirs
} else {
foreach(dir, invoker.public_include_dirs) {
cflags += [
"-isystem",
rebase_path(dir),
]
}
}
} else {
not_needed(invoker, "*")
}
include_dirs = invoker.public_include_dirs
}
source_set(target_name) {
forward_variables_from(invoker, "*", [ "public_include_dirs" ])
public_configs = [ ":" + target_name + "_public" ]
if (enabled) {
forward_variables_from(invoker, "*", [ "public_include_dirs" ])
public_configs = [ ":" + target_name + "_public" ]
# Warnings are just noise if we're not maintaining the code.
if (is_win) {
cflags = [ "/w" ]
} else {
cflags = [ "-w" ]
# Warnings are just noise if we're not maintaining the code.
if (is_win) {
cflags = [ "/w" ]
} else {
cflags = [ "-w" ]
}
}
}
}