Flutter Engine
The Flutter Engine
MSKPSlide.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2021 Google LLC
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
9
14#include "include/core/SkRect.h"
18
19#include <cstddef>
20#include <utility>
21
22#include "imgui.h"
23
25 : MSKPSlide(name, SkStream::MakeFromFile(path.c_str())) {}
26
27MSKPSlide::MSKPSlide(const SkString& name, std::unique_ptr<SkStreamSeekable> stream)
28 : fStream(std::move(stream)) {
29 fName = name;
30}
31
33 return fPlayer ? fPlayer->maxDimensions() : SkISize{0, 0};
34}
35
37 if (!fPlayer) {
38 ImGui::Text("Could not read mskp file %s.\n", fName.c_str());
39 return;
40 }
41 ImGui::Begin("MSKP");
42
43 ImGui::BeginGroup();
44 // Play/Pause button
45 if (ImGui::Button(fPaused ? "Play " : "Pause")) {
46 fPaused = !fPaused;
47 if (fPaused) {
48 // This will ensure that when playback is unpaused we start on the current frame.
49 fLastFrameTime = -1;
50 }
51 }
52 // Control the frame rate of MSKP playback
53 ImGui::Text("FPS: "); ImGui::SameLine();
54 ImGui::RadioButton( "1", &fFPS, 1); ImGui::SameLine();
55 ImGui::RadioButton( "15", &fFPS, 15); ImGui::SameLine();
56 ImGui::RadioButton( "30", &fFPS, 30); ImGui::SameLine();
57 ImGui::RadioButton( "60", &fFPS, 60); ImGui::SameLine();
58 ImGui::RadioButton("120", &fFPS, 120); ImGui::SameLine();
59 ImGui::RadioButton("1:1", &fFPS, -1); // Draw one MSKP frame for each real viewer frame.
60 if (fFPS < 0) {
61 // Like above, will cause onAnimate() to resume at current frame when FPS is changed
62 // back to another frame rate.
63 fLastFrameTime = -1;
64 }
65 // Frame control. Slider and +/- buttons. Ctrl-Click slider to type frame number.
66 ImGui::Text("Frame:");
67 ImGui::SameLine();
68 ImGui::PushButtonRepeat(true); // Enable click-and-hold for frame arrows.
69 int oldFrame = fFrame;
70 if (ImGui::ArrowButton("-mksp_frame", ImGuiDir_Left)) {
71 fFrame = (fFrame + fPlayer->numFrames() - 1)%fPlayer->numFrames();
72 }
73 ImGui::SameLine();
74 if (ImGui::SliderInt("##msk_frameslider", &fFrame, 0, fPlayer->numFrames()-1, "% 3d")) {
75 fFrame = SkTPin(fFrame, 0, fPlayer->numFrames() - 1);
76 }
77 ImGui::SameLine();
78 if (ImGui::ArrowButton("+mskp_frame", ImGuiDir_Right)) {
79 fFrame = (fFrame + 1)%fPlayer->numFrames();
80 }
81 if (fFrame != oldFrame) {
82 // When manually adjusting frames force layers to redraw.
83 this->redrawLayers();
84 }
85
86 ImGui::PopButtonRepeat();
87 ImGui::EndGroup();
88
89 ImGui::BeginGroup();
90 ImGui::Checkbox("Show Frame Bounds", &fShowFrameBounds);
91 ImGui::SetNextItemWidth(200);
92 ImGui::ColorPicker4("background", fBackgroundColor, ImGuiColorEditFlags_AlphaBar);
93 // ImGui lets user enter out of range values by typing.
94 for (float& component : fBackgroundColor) {
95 component = SkTPin(component, 0.f, 1.f);
96 }
97 ImGui::EndGroup();
98
99 // UI for visualizing contents of offscreen layers.
100 ImGui::Text("Offscreen Layers "); ImGui::SameLine();
101 ImGui::Checkbox("List All Layers", &fListAllLayers);
102 ImGui::RadioButton("root", &fDrawLayerID, -1);
103 const std::vector<int>& layerIDs = fListAllLayers ? fAllLayerIDs : fFrameLayerIDs[fFrame];
104 fLayerIDStrings.resize(layerIDs.size());
105 for (size_t i = 0; i < layerIDs.size(); ++i) {
106 fLayerIDStrings[i] = SkStringPrintf("%d", layerIDs[i]);
107 ImGui::RadioButton(fLayerIDStrings[i].c_str(), &fDrawLayerID, layerIDs[i]);
108 }
109 ImGui::End();
110
111 auto bounds = SkIRect::MakeSize(fPlayer->frameDimensions(fFrame));
112
113 if (fShowFrameBounds) {
114 SkPaint boundsPaint;
115 boundsPaint.setStyle(SkPaint::kStroke_Style);
116 boundsPaint.setColor(SK_ColorRED);
117 boundsPaint.setStrokeWidth(0.f);
118 boundsPaint.setAntiAlias(true);
119 // Outset so that at default scale we draw at pixel centers of the rows/cols surrounding the
120 // bounds.
121 canvas->drawRect(SkRect::Make(bounds).makeOutset(0.5f, 0.5f), boundsPaint);
122 }
123
124 canvas->save();
125 if (fDrawLayerID >= 0) {
126 // clip out the root layer content, but still call playFrame so layer contents are updated
127 // to fFrame.
129 }
130 canvas->clipIRect(bounds);
131 canvas->clear(SkColor4f{fBackgroundColor[0],
132 fBackgroundColor[1],
133 fBackgroundColor[2],
134 fBackgroundColor[3]});
135 fPlayer->playFrame(canvas, fFrame);
136 canvas->restore();
137
138 if (fDrawLayerID >= 0) {
139 if (sk_sp<SkImage> layerImage = fPlayer->layerSnapshot(fDrawLayerID)) {
140 canvas->save();
141 canvas->clipIRect(SkIRect::MakeSize(layerImage->dimensions()));
142 canvas->clear(SkColor4f{fBackgroundColor[0],
143 fBackgroundColor[1],
144 fBackgroundColor[2],
145 fBackgroundColor[3]});
146 canvas->drawImage(std::move(layerImage), 0, 0);
147 canvas->restore();
148 }
149 return;
150 }
151}
152
153bool MSKPSlide::animate(double nanos) {
154 if (!fPlayer || fPaused) {
155 return false;
156 }
157 if (fLastFrameTime < 0) {
158 // We're coming off being paused or switching from 1:1 mode to steady FPS. Advance 1 frame
159 // and reset the frame time to start accumulating time from now.
160 fFrame = (fFrame + 1)%fPlayer->numFrames();
161 fLastFrameTime = nanos;
162 return this->fPlayer->numFrames() > 1;
163 }
164 if (fFPS < 0) {
165 // 1:1 mode. Always draw the next frame on each animation cycle.
166 fFrame = (fFrame + 1)%fPlayer->numFrames();
167 return this->fPlayer->numFrames() > 1;
168 }
169 double elapsed = nanos - fLastFrameTime;
170 double frameTime = 1E9/fFPS;
171 int framesToAdvance = elapsed/frameTime;
172 fFrame = fFrame + framesToAdvance;
173 if (fFrame >= fPlayer->numFrames()) {
174 this->redrawLayers();
175 }
176 fFrame %= fPlayer->numFrames();
177 // Instead of just adding elapsed, note the time when this frame should have begun.
178 fLastFrameTime += framesToAdvance*frameTime;
179 return framesToAdvance > 0;
180}
181
183 if (!fStream) {
184 return;
185 }
186 fStream->rewind();
187 fPlayer = MSKPPlayer::Make(fStream.get());
188 if (!fPlayer) {
189 return;
190 }
191 fAllLayerIDs = fPlayer->layerIDs();
192 fFrameLayerIDs.clear();
193 fFrameLayerIDs.resize(fPlayer->numFrames());
194 for (int i = 0; i < fPlayer->numFrames(); ++i) {
195 fFrameLayerIDs[i] = fPlayer->layerIDs(i);
196 }
197}
198
199void MSKPSlide::unload() { fPlayer.reset(); }
200
202 if (fPlayer) {
203 fPlayer->resetLayers();
204 }
205}
206
207void MSKPSlide::redrawLayers() {
208 if (fDrawLayerID >= 0) {
209 // Completely reset the layers so that we won't see content from later frames on layers
210 // that haven't been visited from frames 0..fFrames.
211 fPlayer->resetLayers();
212 } else {
213 // Just rewind layers so that we redraw any layer from scratch on the next frame that
214 // updates it. Important for benchmarking/profiling as otherwise if a layer is only
215 // drawn once in the frame sequence then it will never be updated after the first play
216 // through. This doesn't reallocate the layer backing stores.
217 fPlayer->rewindLayers();
218 }
219}
constexpr SkColor SK_ColorRED
Definition: SkColor.h:126
SK_API SkString SkStringPrintf(const char *format,...) SK_PRINTF_LIKE(1
Creates a new string and writes into it using a printf()-style format.
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
Definition: SkTPin.h:19
static std::unique_ptr< MSKPPlayer > Make(SkStreamSeekable *stream)
Definition: MSKPPlayer.cpp:386
bool animate(double nanos) override
Definition: MSKPSlide.cpp:153
void draw(SkCanvas *canvas) override
Definition: MSKPSlide.cpp:36
void unload() override
Definition: MSKPSlide.cpp:199
SkISize getDimensions() const override
Definition: MSKPSlide.cpp:32
void load(SkScalar winWidth, SkScalar winHeight) override
Definition: MSKPSlide.cpp:182
void gpuTeardown() override
Definition: MSKPSlide.cpp:201
MSKPSlide(const SkString &name, const SkString &path)
Definition: MSKPSlide.cpp:24
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void restore()
Definition: SkCanvas.cpp:461
void clipIRect(const SkIRect &irect, SkClipOp op=SkClipOp::kIntersect)
Definition: SkCanvas.h:991
void clear(SkColor color)
Definition: SkCanvas.h:1199
int save()
Definition: SkCanvas.cpp:447
void drawImage(const SkImage *image, SkScalar left, SkScalar top)
Definition: SkCanvas.h:1528
void setStyle(Style style)
Definition: SkPaint.cpp:105
void setColor(SkColor color)
Definition: SkPaint.cpp:119
void setAntiAlias(bool aa)
Definition: SkPaint.h:170
@ kStroke_Style
set to stroke geometry
Definition: SkPaint.h:194
void setStrokeWidth(SkScalar width)
Definition: SkPaint.cpp:159
const char * c_str() const
Definition: SkString.h:133
SkString fName
Definition: Slide.h:54
float SkScalar
Definition: extension.cpp:12
Optional< SkRect > bounds
Definition: SkRecords.h:189
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
Definition: ref_ptr.h:256
static constexpr SkIRect MakeSize(const SkISize &size)
Definition: SkRect.h:66
static constexpr SkIRect MakeEmpty()
Definition: SkRect.h:45
Definition: SkSize.h:16
static SkRect Make(const SkISize &size)
Definition: SkRect.h:669