blob: 23f1a219f1cb0d14b289115152b31ba2385cd55f [file] [log] [blame]
Florin Malita76a076b2018-02-15 18:40:48 -05001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SlideDir.h"
9
10#include "SkAnimTimer.h"
11#include "SkCanvas.h"
12#include "SkMakeUnique.h"
13#include "SkSGColor.h"
14#include "SkSGDraw.h"
15#include "SkSGGroup.h"
16#include "SkSGRenderNode.h"
17#include "SkSGScene.h"
18#include "SkSGText.h"
19#include "SkSGTransform.h"
20#include "SkTypeface.h"
21
22namespace {
23
24static constexpr float kAspectRatio = 1.5f;
25static constexpr float kLabelSize = 12.0f;
26static constexpr SkSize kPadding = { 12.0f, 24.0f };
27
28class SlideAdapter final : public sksg::RenderNode {
29public:
30 explicit SlideAdapter(sk_sp<Slide> slide)
31 : fSlide(std::move(slide)) {
32 SkASSERT(fSlide);
33 }
34
35 std::unique_ptr<sksg::Animator> makeForwardingAnimator() {
36 // Trivial sksg::Animator -> skottie::Animation tick adapter
37 class ForwardingAnimator final : public sksg::Animator {
38 public:
39 explicit ForwardingAnimator(sk_sp<SlideAdapter> adapter)
40 : fAdapter(std::move(adapter)) {}
41
42 protected:
43 void onTick(float t) override {
44 fAdapter->tick(SkScalarRoundToInt(t));
45 }
46
47 private:
48 sk_sp<SlideAdapter> fAdapter;
49 };
50
51 return skstd::make_unique<ForwardingAnimator>(sk_ref_sp(this));
52 }
53
54protected:
55 SkRect onRevalidate(sksg::InvalidationController* ic, const SkMatrix& ctm) override {
56 const auto isize = fSlide->getDimensions();
57 return SkRect::MakeIWH(isize.width(), isize.height());
58 }
59
60 void onRender(SkCanvas* canvas) const override {
61 fSlide->draw(canvas);
62 }
63
64private:
65 void tick(SkMSec t) {
66 fSlide->animate(SkAnimTimer(0, t * 1e6, SkAnimTimer::kRunning_State));
67 this->invalidate();
68 }
69
70 const sk_sp<Slide> fSlide;
71
72 using INHERITED = sksg::RenderNode;
73};
74
75} // namespace
76
77struct SlideDir::Rec {
78 sk_sp<sksg::Matrix> fMatrix;
79 SkRect fRect;
80};
81
82SlideDir::SlideDir(const SkString& name, SkTArray<sk_sp<Slide>, true>&& slides, int columns)
83 : fSlides(std::move(slides))
84 , fColumns(columns) {
85 fName = name;
86}
87
88static sk_sp<sksg::RenderNode> MakeLabel(const SkString& txt, const SkRect& dst) {
89 auto text = sksg::Text::Make(nullptr, txt);
90 text->setFlags(SkPaint::kAntiAlias_Flag);
91 text->setSize(kLabelSize);
92 text->setAlign(SkPaint::kCenter_Align);
93 text->setPosition(SkPoint::Make(dst.centerX(), dst.bottom()));
94
95 return sksg::Draw::Make(std::move(text), sksg::Color::Make(SK_ColorBLACK));
96}
97
98void SlideDir::load(SkScalar winWidth, SkScalar winHeight) {
99 // Build a global scene using transformed animation fragments:
100 //
101 // [Group(root)]
102 // [Transform]
103 // [Group]
104 // [AnimationWrapper]
105 // [Draw]
106 // [Text]
107 // [Color]
108 // [Transform]
109 // [Group]
110 // [AnimationWrapper]
111 // [Draw]
112 // [Text]
113 // [Color]
114 // ...
115 //
116
117 fSize = SkSize::Make(winWidth, winHeight).toCeil();
118
119 const auto cellWidth = winWidth / fColumns,
120 cellHeight = cellWidth / kAspectRatio;
121
122 sksg::AnimatorList sceneAnimators;
123 auto root = sksg::Group::Make();
124
125 for (int i = 0; i < fSlides.count(); ++i) {
126 const auto& slide = fSlides[i];
127 slide->load(winWidth, winHeight);
128
129 const auto slideSize = slide->getDimensions();
130 const auto cell = SkRect::MakeXYWH(cellWidth * (i % fColumns),
131 cellHeight * (i / fColumns),
132 cellWidth,
133 cellHeight),
134 slideRect = cell.makeInset(kPadding.width(), kPadding.height());
135
136 auto matrix = sksg::Matrix::Make(
137 SkMatrix::MakeRectToRect(SkRect::MakeIWH(slideSize.width(), slideSize.height()),
138 slideRect,
139 SkMatrix::kCenter_ScaleToFit));
140
141 auto adapter = sk_make_sp<SlideAdapter>(slide);
142 auto slideGrp = sksg::Group::Make();
143 slideGrp->addChild(sksg::Transform::Make(adapter, matrix));
144 slideGrp->addChild(MakeLabel(slide->getName(), cell));
145
146 sceneAnimators.push_back(adapter->makeForwardingAnimator());
147 root->addChild(std::move(slideGrp));
148
149 fRecs.push_back({ matrix, slideRect });
150 }
151
152 fScene = sksg::Scene::Make(std::move(root), std::move(sceneAnimators));
153}
154
155void SlideDir::unload() {
156 for (const auto& slide : fSlides) {
157 slide->unload();
158 }
159
160 fRecs.reset();
161 fScene.reset();
162 fTimeBase = 0;
163}
164
165SkISize SlideDir::getDimensions() const {
166 return fSize;
167}
168
169void SlideDir::draw(SkCanvas* canvas) {
170 fScene->render(canvas);
171}
172
173bool SlideDir::animate(const SkAnimTimer& timer) {
174 if (fTimeBase == 0) {
175 // Reset the animation time.
176 fTimeBase = timer.msec();
177 }
178 fScene->animate(timer.msec() - fTimeBase);
179
180 return true;
181}
182
183bool SlideDir::onChar(SkUnichar c) {
184 return false;
185}
186
187bool SlideDir::onMouse(SkScalar x, SkScalar y, sk_app::Window::InputState, uint32_t modifiers) {
188 return false;
189}