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>. 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 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 52 NIMASlide::~NIMASlide() {} 53 54 SkISize NIMASlide::getDimensions() const { 55 return SkISize::MakeEmpty(); // TODO 56 } 57 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 82 void NIMASlide::load(SkScalar winWidth, SkScalar winHeight) { 83 this->resetActor(); 84 } 85 86 void NIMASlide::unload() { 87 // Discard resources. 88 fActor.reset(nullptr); 89 } 90 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 100 bool NIMASlide::onChar(SkUnichar c) { 101 return false; 102 } 103 104 bool NIMASlide::onMouse(SkScalar x, SkScalar y, Window::InputState state, uint32_t modifiers) { 105 return false; 106 } 107 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 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