From 72f6c42ed8f41fbe78914beda9ed38005808b720 Mon Sep 17 00:00:00 2001 From: Jorge Betancourt Date: Tue, 3 May 2022 15:23:16 -0400 Subject: [PATCH] [skottie] render particles through transform tracker decorator Change the way we transform the matrix on render for specific decorations Change-Id: I3112c38a95cd1473e9e9c5bfff9eac09e20f6016 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/536101 Commit-Queue: Jorge Betancourt Reviewed-by: Florin Malita --- tools/viewer/BUILD.bazel | 3 ++ tools/viewer/SkottieSlide.cpp | 68 +++++++++++++++++++++++++++++++---- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/tools/viewer/BUILD.bazel b/tools/viewer/BUILD.bazel index 48392f4ac1..9a68b726b8 100644 --- a/tools/viewer/BUILD.bazel +++ b/tools/viewer/BUILD.bazel @@ -262,11 +262,14 @@ generated_cc_atom( "//include/private:SkNoncopyable_hdr", "//include/private:SkTPin_hdr", "//modules/audioplayer:SkAudioPlayer_hdr", + "//modules/particles/include:SkParticleEffect_hdr", + "//modules/particles/include:SkParticleSerialization_hdr", "//modules/skottie/include:SkottieProperty_hdr", "//modules/skottie/include:Skottie_hdr", "//modules/skottie/utils:SkottieUtils_hdr", "//modules/skresources/include:SkResources_hdr", "//src/utils:SkOSPath_hdr", + "//tools:Resources_hdr", "//tools/timer:TimeUtils_hdr", ], ) diff --git a/tools/viewer/SkottieSlide.cpp b/tools/viewer/SkottieSlide.cpp index 8659ee94cd..046d57672d 100644 --- a/tools/viewer/SkottieSlide.cpp +++ b/tools/viewer/SkottieSlide.cpp @@ -15,11 +15,14 @@ #include "include/private/SkNoncopyable.h" #include "include/private/SkTPin.h" #include "modules/audioplayer/SkAudioPlayer.h" +#include "modules/particles/include/SkParticleEffect.h" +#include "modules/particles/include/SkParticleSerialization.h" #include "modules/skottie/include/Skottie.h" #include "modules/skottie/include/SkottieProperty.h" #include "modules/skottie/utils/SkottieUtils.h" #include "modules/skresources/include/SkResources.h" #include "src/utils/SkOSPath.h" +#include "tools/Resources.h" #include "tools/timer/TimeUtils.h" #include @@ -81,7 +84,9 @@ class Decorator : public SkNoncopyable { public: virtual ~Decorator() = default; - virtual void render(SkCanvas*) = 0; + // We pass in the Matrix and have the Decorator handle using it independently + // This is so decorators like particle effects can keep position on screen after moving. + virtual void render(SkCanvas*, double, const SkMatrix) = 0; }; class SimpleMarker final : public Decorator { @@ -90,7 +95,8 @@ public: static std::unique_ptr Make() { return std::make_unique(); } - void render(SkCanvas* canvas) override { + void render(SkCanvas* canvas, double t, const SkMatrix transform) override { + canvas->concat(transform); SkPaint p; p.setAntiAlias(true); @@ -104,11 +110,56 @@ public: } }; +class ParticleMarker final : public Decorator { +public: + ~ParticleMarker() override = default; + + static std::unique_ptr MakeConfetti() { return std::make_unique("confetti.json"); } + static std::unique_ptr MakeSine() { return std::make_unique("sinusoidal_emitter.json"); } + + explicit ParticleMarker(const char* effect_file) { + SkParticleEffect::RegisterParticleTypes(); + auto params = sk_sp(); + params.reset(new SkParticleEffectParams()); + auto effectJsonPath = SkOSPath::Join(GetResourcePath("particles").c_str(), effect_file); + if (auto fileData = SkData::MakeFromFileName(effectJsonPath.c_str())) { + skjson::DOM dom(static_cast(fileData->data()), fileData->size()); + SkFromJsonVisitor fromJson(dom.root()); + params->visitFields(&fromJson); + // We can pass in a null pointer because the SkCircleDrawable used in confetti.json + // doesn't use the resource provider + params->prepare(nullptr); + } else { + SkDebugf("no particle effect file found at: %s\n", effectJsonPath.c_str()); + } + fEffect = sk_make_sp(params); + } + + void render(SkCanvas* canvas, double t, SkMatrix transform) override { + if (!fStarted || t < 0.01) { + fStarted = true; + fEffect->start(t, true, { 0, 0 }, { 0, -1 }, 1, { 0, 0 }, 0, + { 1, 1, 1, 1 }, 0, 0); + fEffect->setPosition({0,0}); + } + SkPoint p = {0,0}; + transform.mapPoints(&p, 1); + fEffect->setPosition(p); + fEffect->update(t); + fEffect->draw(canvas); + } +private: + sk_sp fEffect; + bool fStarted = false; +}; + static const struct DecoratorRec { const char* fName; std::unique_ptr(*fFactory)(); } kDecorators[] = { - { "Simple marker", SimpleMarker::Make } + { "Simple marker", SimpleMarker::Make }, + { "Confetti", ParticleMarker::MakeConfetti }, + { "Sine Wave", ParticleMarker::MakeSine }, }; } // namespace @@ -152,7 +203,7 @@ public: ImGui::End(); } - void renderTracker(SkCanvas* canvas, const SkSize& win_size, const SkSize& anim_size) const { + void renderTracker(SkCanvas* canvas, double time, const SkSize& win_size, const SkSize& anim_size) const { if (!fTransformSelect) { return; } @@ -170,10 +221,9 @@ public: SkAutoCanvasRestore acr(canvas, true); canvas->concat(viewer_matrix); - canvas->concat(m); SkASSERT(fDecorator); - fDecorator->render(canvas); + fDecorator->render(canvas, time, m); } private: @@ -336,7 +386,11 @@ void SkottieSlide::draw(SkCanvas* canvas) { fFrameTimes[frame_index] = static_cast((SkTime::GetNSecs() - t0) * 1e-6); } - fTransformTracker->renderTracker(canvas, fWinSize, fAnimation->size()); + double fr = 60; + if (fFrameRate != 0) { + fr = fFrameRate; + } + fTransformTracker->renderTracker(canvas, fCurrentFrame/fr, fWinSize, fAnimation->size()); if (fShowAnimationStats) { draw_stats_box(canvas, fAnimationStats);