aboutsummaryrefslogtreecommitdiffhomepage
path: root/samplecode
diff options
context:
space:
mode:
authorGravatar Brian Osman <brianosman@google.com>2018-06-19 16:05:09 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-06-19 20:30:28 +0000
commitc069a57301a468dbc45f3f3775b623e5532f9398 (patch)
tree4c067efbba58df8f6333f80b73924ae0f6e24843 /samplecode
parent644341af03d22dfe10e8e6c47e0aa21f5346031b (diff)
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>
Diffstat (limited to 'samplecode')
-rw-r--r--samplecode/Nima.cpp180
-rw-r--r--samplecode/Nima.h54
-rw-r--r--samplecode/SampleNima.cpp72
3 files changed, 306 insertions, 0 deletions
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 <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);
+}
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 <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
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 <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);