From c069a57301a468dbc45f3f3775b623e5532f9398 Mon Sep 17 00:00:00 2001 From: Brian Osman Date: Tue, 19 Jun 2018 16:05:09 -0400 Subject: 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 Reviewed-by: Mike Klein Reviewed-by: Brian Osman --- BUILD.gn | 3 + DEPS | 2 + gn/samples.gni | 11 +++ resources/nima/Robot.nima | Bin 0 -> 31590 bytes resources/nima/Robot.png | Bin 0 -> 117075 bytes samplecode/Nima.cpp | 180 ++++++++++++++++++++++++++++++++++++++++++ samplecode/Nima.h | 54 +++++++++++++ samplecode/SampleNima.cpp | 72 +++++++++++++++++ third_party/Nima-Cpp/BUILD.gn | 101 ++++++++++++++++++++++++ third_party/third_party.gni | 37 ++++++--- 10 files changed, 450 insertions(+), 10 deletions(-) create mode 100644 resources/nima/Robot.nima create mode 100644 resources/nima/Robot.png create mode 100644 samplecode/Nima.cpp create mode 100644 samplecode/Nima.h create mode 100644 samplecode/SampleNima.cpp create mode 100644 third_party/Nima-Cpp/BUILD.gn diff --git a/BUILD.gn b/BUILD.gn index 3f58f4480b..a433b9295e 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -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", ] } diff --git a/DEPS b/DEPS index 0eeac33c1c..ebc269666a 100644 --- a/DEPS +++ b/DEPS @@ -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" ] diff --git a/gn/samples.gni b/gn/samples.gni index 1a4002f82c..ce73ab8d84 100644 --- a/gn/samples.gni +++ b/gn/samples.gni @@ -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", + ] +} diff --git a/resources/nima/Robot.nima b/resources/nima/Robot.nima new file mode 100644 index 0000000000..4e56985c6a Binary files /dev/null and b/resources/nima/Robot.nima differ diff --git a/resources/nima/Robot.png b/resources/nima/Robot.png new file mode 100644 index 0000000000..595616aa2c Binary files /dev/null and b/resources/nima/Robot.png differ diff --git a/samplecode/Nima.cpp b/samplecode/Nima.cpp new file mode 100644 index 0000000000..4ac7d86137 --- /dev/null +++ b/samplecode/Nima.cpp @@ -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 + +#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)); + + // 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; + + // 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); +} diff --git a/samplecode/Nima.h b/samplecode/Nima.h new file mode 100644 index 0000000000..0017fcf59c --- /dev/null +++ b/samplecode/Nima.h @@ -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 +#include +#include + +#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 fTexture; + std::vector fActorImages; + std::unique_ptr fPaint; + + typedef nima::Actor INHERITED; +}; + +class SampleActorImage { +public: + SampleActorImage(nima::ActorImage* actorImage, sk_sp 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 fTexture; + SkPaint* fPaint; +}; + +#endif diff --git a/samplecode/SampleNima.cpp b/samplecode/SampleNima.cpp new file mode 100644 index 0000000000..ec7813b5a9 --- /dev/null +++ b/samplecode/SampleNima.cpp @@ -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 +#include + +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("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 fActor; + ActorAnimation* fAnimation = nullptr; + + typedef SampleView INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static SkView* MyFactory() { return new NimaView; } +static SkViewRegister reg(MyFactory); diff --git a/third_party/Nima-Cpp/BUILD.gn b/third_party/Nima-Cpp/BUILD.gn new file mode 100644 index 0000000000..f3dc8b2309 --- /dev/null +++ b/third_party/Nima-Cpp/BUILD.gn @@ -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 +} diff --git a/third_party/third_party.gni b/third_party/third_party.gni index 7aaf63586f..384eeed580 100644 --- a/third_party/third_party.gni +++ b/third_party/third_party.gni @@ -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" ] + } } } } -- cgit v1.2.3