1 /*
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 "NIMASlide.h"
9
10 #include "Resources.h"
11 #include "SkAnimTimer.h"
12 #include "SkOSPath.h"
13 #include "imgui.h"
14 #include "nima/NimaActor.h"
15
16 #include <algorithm>
17 #include <cmath>
18
19 using namespace sk_app;
20 using namespace nima;
21
22 // ImGui expects an array of const char* when displaying a ListBox. This function is for an
23 // overload of ImGui::ListBox that takes a getter so that ListBox works with
24 // std::vector<std::string>.
vector_getter(void * v,int index,const char ** out)25 static bool vector_getter(void* v, int index, const char** out) {
26 auto vector = reinterpret_cast<std::vector<std::string>*>(v);
27 *out = vector->at(index).c_str();
28 return true;
29 }
30
31 //////////////////////////////////////////////////////////////////////////////////////////////////
32
NIMASlide(const SkString & name,const SkString & path)33 NIMASlide::NIMASlide(const SkString& name, const SkString& path)
34 : fBasePath()
35 , fActor(nullptr)
36 , fAnimationIndex(0)
37 , fPlaying(true)
38 , fTime(0.0f)
39 , fRenderFlags(0) {
40 fName = name;
41
42 // Get the path components.
43 SkString baseName = SkOSPath::Basename(path.c_str());
44 baseName.resize(baseName.size() - 5);
45 SkString dirName = SkOSPath::Dirname(path.c_str());
46 SkString basePath = SkOSPath::Join(dirName.c_str(), baseName.c_str());
47
48 // Save the base path.
49 fBasePath = std::string(basePath.c_str());
50 }
51
~NIMASlide()52 NIMASlide::~NIMASlide() {}
53
getDimensions() const54 SkISize NIMASlide::getDimensions() const {
55 return SkISize::MakeEmpty(); // TODO
56 }
57
draw(SkCanvas * canvas)58 void NIMASlide::draw(SkCanvas* canvas) {
59 canvas->save();
60
61 for (int i = 0; i < 10; i ++) {
62 for (int j = 0; j < 10; j ++) {
63 canvas->save();
64
65 canvas->translate(1250 - 250 * i, 1250 - 250 * j);
66 canvas->scale(0.5, -0.5);
67
68 // Render the actor.
69 fActor->setAnimation(fAnimationIndex);
70 fActor->render(canvas, fRenderFlags);
71
72 canvas->restore();
73 }
74 }
75
76 canvas->restore();
77
78 // Render the GUI.
79 this->renderGUI();
80 }
81
load(SkScalar winWidth,SkScalar winHeight)82 void NIMASlide::load(SkScalar winWidth, SkScalar winHeight) {
83 this->resetActor();
84 }
85
unload()86 void NIMASlide::unload() {
87 // Discard resources.
88 fActor.reset(nullptr);
89 }
90
animate(const SkAnimTimer & timer)91 bool NIMASlide::animate(const SkAnimTimer& timer) {
92 // Apply the animation.
93 if (fActor) {
94 float time = std::fmod(timer.secs(), fActor->duration());
95 fActor->seek(time);
96 }
97 return true;
98 }
99
onChar(SkUnichar c)100 bool NIMASlide::onChar(SkUnichar c) {
101 return false;
102 }
103
onMouse(SkScalar x,SkScalar y,Window::InputState state,uint32_t modifiers)104 bool NIMASlide::onMouse(SkScalar x, SkScalar y, Window::InputState state, uint32_t modifiers) {
105 return false;
106 }
107
resetActor()108 void NIMASlide::resetActor() {
109 // Create the actor.
110 std::string nimaPath = fBasePath + ".nima";
111 std::string texturePath = fBasePath + ".png";
112
113 fActor = std::make_unique<NimaActor>(nimaPath, texturePath);
114 }
115
renderGUI()116 void NIMASlide::renderGUI() {
117 ImGui::SetNextWindowSize(ImVec2(300, 0));
118 ImGui::Begin("NIMA");
119
120 // List of animations.
121 auto animations = const_cast<std::vector<std::string>&>(fActor->getAnimationNames());
122 ImGui::PushItemWidth(-1);
123 if (ImGui::ListBox("Animations",
124 &fAnimationIndex,
125 vector_getter,
126 reinterpret_cast<void*>(&animations),
127 animations.size(),
128 5)) {
129 resetActor();
130 }
131
132 // Playback control.
133 ImGui::Spacing();
134 if (ImGui::Button("Play")) {
135 fPlaying = true;
136 }
137 ImGui::SameLine();
138 if (ImGui::Button("Pause")) {
139 fPlaying = false;
140 }
141
142 // Time slider.
143 ImGui::PushItemWidth(-1);
144 ImGui::SliderFloat("Time", &fTime, 0.0f, fActor->duration(), "Time: %.3f");
145
146 // Backend control.
147 int useImmediate = SkToBool(fRenderFlags & kImmediate_RenderFlag);
148 ImGui::Spacing();
149 ImGui::RadioButton("Skia Backend", &useImmediate, 0);
150 ImGui::RadioButton("Immediate Backend", &useImmediate, 1);
151 if (useImmediate) {
152 fRenderFlags |= kImmediate_RenderFlag;
153 } else {
154 fRenderFlags &= ~kImmediate_RenderFlag;
155 }
156
157 // Cache control.
158 bool useCache = SkToBool(fRenderFlags & kCache_RenderFlag);
159 ImGui::Spacing();
160 ImGui::Checkbox("Cache Vertices", &useCache);
161 if (useCache) {
162 fRenderFlags |= kCache_RenderFlag;
163 } else {
164 fRenderFlags &= ~kCache_RenderFlag;
165 }
166
167 // Bounding box toggle.
168 bool drawBounds = SkToBool(fRenderFlags & kBounds_RenderFlag);
169 ImGui::Spacing();
170 ImGui::Checkbox("Draw Bounds", &drawBounds);
171 if (drawBounds) {
172 fRenderFlags |= kBounds_RenderFlag;
173 } else {
174 fRenderFlags &= ~kBounds_RenderFlag;
175 }
176
177 ImGui::End();
178 }
179