jvanverth | 9f37246 | 2016-04-06 06:08:59 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2016 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 | |
jvanverth | 3452426 | 2016-05-04 13:49:13 -0700 | [diff] [blame] | 8 | #include "Viewer.h" |
jvanverth | 9f37246 | 2016-04-06 06:08:59 -0700 | [diff] [blame] | 9 | |
jvanverth | 2bb3b6d | 2016-04-08 07:24:09 -0700 | [diff] [blame] | 10 | #include "GMSlide.h" |
| 11 | #include "SKPSlide.h" |
jvanverth | 9f37246 | 2016-04-06 06:08:59 -0700 | [diff] [blame] | 12 | |
jvanverth | 2bb3b6d | 2016-04-08 07:24:09 -0700 | [diff] [blame] | 13 | #include "SkCanvas.h" |
| 14 | #include "SkCommonFlags.h" |
| 15 | #include "SkOSFile.h" |
| 16 | #include "SkRandom.h" |
| 17 | #include "SkStream.h" |
jvanverth | 9f37246 | 2016-04-06 06:08:59 -0700 | [diff] [blame] | 18 | |
jvanverth | 3452426 | 2016-05-04 13:49:13 -0700 | [diff] [blame] | 19 | using namespace sk_app; |
| 20 | |
jvanverth | 9f37246 | 2016-04-06 06:08:59 -0700 | [diff] [blame] | 21 | Application* Application::Create(int argc, char** argv, void* platformData) { |
jvanverth | 3452426 | 2016-05-04 13:49:13 -0700 | [diff] [blame] | 22 | return new Viewer(argc, argv, platformData); |
jvanverth | 9f37246 | 2016-04-06 06:08:59 -0700 | [diff] [blame] | 23 | } |
| 24 | |
jvanverth | 9f37246 | 2016-04-06 06:08:59 -0700 | [diff] [blame] | 25 | static void on_paint_handler(SkCanvas* canvas, void* userData) { |
jvanverth | 3452426 | 2016-05-04 13:49:13 -0700 | [diff] [blame] | 26 | Viewer* vv = reinterpret_cast<Viewer*>(userData); |
jvanverth | 9f37246 | 2016-04-06 06:08:59 -0700 | [diff] [blame] | 27 | |
| 28 | return vv->onPaint(canvas); |
| 29 | } |
| 30 | |
liyuqian | d3cdbca | 2016-05-17 12:44:20 -0700 | [diff] [blame] | 31 | static bool on_touch_handler(int owner, Window::InputState state, float x, float y, void* userData) |
| 32 | { |
| 33 | Viewer* viewer = reinterpret_cast<Viewer*>(userData); |
| 34 | |
| 35 | return viewer->onTouch(owner, state, x, y); |
| 36 | } |
| 37 | |
liyuqian | e5a6cd9 | 2016-05-27 08:52:52 -0700 | [diff] [blame] | 38 | static void on_ui_state_changed_handler(const SkString& stateName, const SkString& stateValue, void* userData) { |
| 39 | Viewer* viewer = reinterpret_cast<Viewer*>(userData); |
| 40 | |
| 41 | return viewer->onUIStateChanged(stateName, stateValue); |
| 42 | } |
| 43 | |
| 44 | DEFINE_bool2(fullscreen, f, true, "Run fullscreen."); |
jvanverth | 2bb3b6d | 2016-04-08 07:24:09 -0700 | [diff] [blame] | 45 | DEFINE_string(key, "", "Space-separated key/value pairs to add to JSON identifying this builder."); |
| 46 | DEFINE_string2(match, m, nullptr, |
| 47 | "[~][^]substring[$] [...] of bench name to run.\n" |
| 48 | "Multiple matches may be separated by spaces.\n" |
| 49 | "~ causes a matching bench to always be skipped\n" |
| 50 | "^ requires the start of the bench to match\n" |
| 51 | "$ requires the end of the bench to match\n" |
| 52 | "^ and $ requires an exact match\n" |
| 53 | "If a bench does not match any list entry,\n" |
| 54 | "it is skipped unless some list entry starts with ~"); |
| 55 | DEFINE_string(skps, "skps", "Directory to read skps from."); |
jvanverth | 85f758c | 2016-05-27 06:47:08 -0700 | [diff] [blame] | 56 | DEFINE_bool(vulkan, true, "Run with Vulkan."); |
jvanverth | 2bb3b6d | 2016-04-08 07:24:09 -0700 | [diff] [blame] | 57 | |
jvanverth | af236b5 | 2016-05-20 06:01:06 -0700 | [diff] [blame] | 58 | const char *kBackendTypeStrings[sk_app::Window::kBackendTypeCount] = { |
| 59 | " [OpenGL]", |
| 60 | " [Vulkan]" |
| 61 | }; |
| 62 | |
liyuqian | e5a6cd9 | 2016-05-27 08:52:52 -0700 | [diff] [blame] | 63 | const char* kName = "name"; |
| 64 | const char* kValue = "value"; |
| 65 | const char* kOptions = "options"; |
| 66 | const char* kSlideStateName = "Slide"; |
| 67 | const char* kBackendStateName = "Backend"; |
| 68 | |
jvanverth | 3452426 | 2016-05-04 13:49:13 -0700 | [diff] [blame] | 69 | Viewer::Viewer(int argc, char** argv, void* platformData) |
jvanverth | c265a92 | 2016-04-08 12:51:45 -0700 | [diff] [blame] | 70 | : fCurrentMeasurement(0) |
| 71 | , fDisplayStats(false) |
jvanverth | af236b5 | 2016-05-20 06:01:06 -0700 | [diff] [blame] | 72 | , fBackendType(sk_app::Window::kVulkan_BackendType) |
egdaniel | 2a0bb0a | 2016-04-11 08:30:40 -0700 | [diff] [blame] | 73 | , fZoomCenterX(0.0f) |
| 74 | , fZoomCenterY(0.0f) |
| 75 | , fZoomLevel(0.0f) |
| 76 | , fZoomScale(SK_Scalar1) |
jvanverth | c265a92 | 2016-04-08 12:51:45 -0700 | [diff] [blame] | 77 | { |
jvanverth | 3d6ed3a | 2016-04-07 11:09:51 -0700 | [diff] [blame] | 78 | memset(fMeasurements, 0, sizeof(fMeasurements)); |
jvanverth | 9f37246 | 2016-04-06 06:08:59 -0700 | [diff] [blame] | 79 | |
jvanverth | 2bb3b6d | 2016-04-08 07:24:09 -0700 | [diff] [blame] | 80 | SkDebugf("Command line arguments: "); |
| 81 | for (int i = 1; i < argc; ++i) { |
| 82 | SkDebugf("%s ", argv[i]); |
| 83 | } |
| 84 | SkDebugf("\n"); |
| 85 | |
| 86 | SkCommandLineFlags::Parse(argc, argv); |
| 87 | |
jvanverth | 85f758c | 2016-05-27 06:47:08 -0700 | [diff] [blame] | 88 | fBackendType = FLAGS_vulkan ? sk_app::Window::kVulkan_BackendType |
| 89 | : sk_app::Window::kNativeGL_BackendType; |
| 90 | |
jvanverth | 9f37246 | 2016-04-06 06:08:59 -0700 | [diff] [blame] | 91 | fWindow = Window::CreateNativeWindow(platformData); |
jvanverth | af236b5 | 2016-05-20 06:01:06 -0700 | [diff] [blame] | 92 | fWindow->attach(fBackendType, DisplayParams()); |
jvanverth | 9f37246 | 2016-04-06 06:08:59 -0700 | [diff] [blame] | 93 | |
| 94 | // register callbacks |
brianosman | 622c8d5 | 2016-05-10 06:50:49 -0700 | [diff] [blame] | 95 | fCommands.attach(fWindow); |
jvanverth | 9f37246 | 2016-04-06 06:08:59 -0700 | [diff] [blame] | 96 | fWindow->registerPaintFunc(on_paint_handler, this); |
liyuqian | d3cdbca | 2016-05-17 12:44:20 -0700 | [diff] [blame] | 97 | fWindow->registerTouchFunc(on_touch_handler, this); |
liyuqian | e5a6cd9 | 2016-05-27 08:52:52 -0700 | [diff] [blame] | 98 | fWindow->registerUIStateChangedFunc(on_ui_state_changed_handler, this); |
jvanverth | 9f37246 | 2016-04-06 06:08:59 -0700 | [diff] [blame] | 99 | |
brianosman | 622c8d5 | 2016-05-10 06:50:49 -0700 | [diff] [blame] | 100 | // add key-bindings |
| 101 | fCommands.addCommand('s', "Overlays", "Toggle stats display", [this]() { |
| 102 | this->fDisplayStats = !this->fDisplayStats; |
| 103 | fWindow->inval(); |
| 104 | }); |
| 105 | fCommands.addCommand('c', "Modes", "Toggle sRGB color mode", [this]() { |
| 106 | DisplayParams params = fWindow->getDisplayParams(); |
| 107 | params.fProfileType = (kLinear_SkColorProfileType == params.fProfileType) |
| 108 | ? kSRGB_SkColorProfileType : kLinear_SkColorProfileType; |
| 109 | fWindow->setDisplayParams(params); |
| 110 | this->updateTitle(); |
| 111 | fWindow->inval(); |
| 112 | }); |
| 113 | fCommands.addCommand(Window::Key::kRight, "Right", "Navigation", "Next slide", [this]() { |
| 114 | int previousSlide = fCurrentSlide; |
| 115 | fCurrentSlide++; |
| 116 | if (fCurrentSlide >= fSlides.count()) { |
| 117 | fCurrentSlide = 0; |
| 118 | } |
| 119 | this->setupCurrentSlide(previousSlide); |
| 120 | }); |
| 121 | fCommands.addCommand(Window::Key::kLeft, "Left", "Navigation", "Previous slide", [this]() { |
| 122 | int previousSlide = fCurrentSlide; |
| 123 | fCurrentSlide--; |
| 124 | if (fCurrentSlide < 0) { |
| 125 | fCurrentSlide = fSlides.count() - 1; |
| 126 | } |
| 127 | this->setupCurrentSlide(previousSlide); |
| 128 | }); |
| 129 | fCommands.addCommand(Window::Key::kUp, "Up", "Transform", "Zoom in", [this]() { |
| 130 | this->changeZoomLevel(1.f / 32.f); |
| 131 | fWindow->inval(); |
| 132 | }); |
| 133 | fCommands.addCommand(Window::Key::kDown, "Down", "Transform", "Zoom out", [this]() { |
| 134 | this->changeZoomLevel(-1.f / 32.f); |
| 135 | fWindow->inval(); |
| 136 | }); |
jvanverth | 85f758c | 2016-05-27 06:47:08 -0700 | [diff] [blame] | 137 | #if 0 // this doesn't seem to work on any platform right now |
jvanverth | af236b5 | 2016-05-20 06:01:06 -0700 | [diff] [blame] | 138 | #ifndef SK_BUILD_FOR_ANDROID |
| 139 | fCommands.addCommand('d', "Modes", "Change rendering backend", [this]() { |
| 140 | fWindow->detach(); |
| 141 | |
| 142 | if (sk_app::Window::kVulkan_BackendType == fBackendType) { |
| 143 | fBackendType = sk_app::Window::kNativeGL_BackendType; |
| 144 | } |
jvanverth | 85f758c | 2016-05-27 06:47:08 -0700 | [diff] [blame] | 145 | // TODO: get Vulkan -> OpenGL working on Windows without swapchain creation failure |
jvanverth | af236b5 | 2016-05-20 06:01:06 -0700 | [diff] [blame] | 146 | //else if (sk_app::Window::kNativeGL_BackendType == fBackendType) { |
| 147 | // fBackendType = sk_app::Window::kVulkan_BackendType; |
| 148 | //} |
| 149 | |
| 150 | fWindow->attach(fBackendType, DisplayParams()); |
| 151 | this->updateTitle(); |
jvanverth | 85f758c | 2016-05-27 06:47:08 -0700 | [diff] [blame] | 152 | fWindow->inval(); |
jvanverth | af236b5 | 2016-05-20 06:01:06 -0700 | [diff] [blame] | 153 | }); |
| 154 | #endif |
jvanverth | 85f758c | 2016-05-27 06:47:08 -0700 | [diff] [blame] | 155 | #endif |
brianosman | 622c8d5 | 2016-05-10 06:50:49 -0700 | [diff] [blame] | 156 | |
jvanverth | 2bb3b6d | 2016-04-08 07:24:09 -0700 | [diff] [blame] | 157 | // set up slides |
| 158 | this->initSlides(); |
| 159 | |
djsollen | 12d62a7 | 2016-04-21 07:59:44 -0700 | [diff] [blame] | 160 | fAnimTimer.run(); |
| 161 | |
jvanverth | 2bb3b6d | 2016-04-08 07:24:09 -0700 | [diff] [blame] | 162 | // set up first frame |
jvanverth | 2bb3b6d | 2016-04-08 07:24:09 -0700 | [diff] [blame] | 163 | fCurrentSlide = 0; |
jvanverth | c265a92 | 2016-04-08 12:51:45 -0700 | [diff] [blame] | 164 | setupCurrentSlide(-1); |
jvanverth | c265a92 | 2016-04-08 12:51:45 -0700 | [diff] [blame] | 165 | |
jvanverth | 9f37246 | 2016-04-06 06:08:59 -0700 | [diff] [blame] | 166 | fWindow->show(); |
| 167 | } |
| 168 | |
jvanverth | 3452426 | 2016-05-04 13:49:13 -0700 | [diff] [blame] | 169 | void Viewer::initSlides() { |
jvanverth | 2bb3b6d | 2016-04-08 07:24:09 -0700 | [diff] [blame] | 170 | const skiagm::GMRegistry* gms(skiagm::GMRegistry::Head()); |
| 171 | while (gms) { |
| 172 | SkAutoTDelete<skiagm::GM> gm(gms->factory()(nullptr)); |
| 173 | |
| 174 | if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, gm->getName())) { |
| 175 | sk_sp<Slide> slide(new GMSlide(gm.release())); |
| 176 | fSlides.push_back(slide); |
| 177 | } |
| 178 | |
| 179 | gms = gms->next(); |
| 180 | } |
| 181 | |
| 182 | // reverse array |
| 183 | for (int i = 0; i < fSlides.count()/2; ++i) { |
| 184 | sk_sp<Slide> temp = fSlides[i]; |
| 185 | fSlides[i] = fSlides[fSlides.count() - i - 1]; |
| 186 | fSlides[fSlides.count() - i - 1] = temp; |
| 187 | } |
| 188 | |
| 189 | // SKPs |
| 190 | for (int i = 0; i < FLAGS_skps.count(); i++) { |
| 191 | if (SkStrEndsWith(FLAGS_skps[i], ".skp")) { |
jvanverth | c265a92 | 2016-04-08 12:51:45 -0700 | [diff] [blame] | 192 | if (SkCommandLineFlags::ShouldSkip(FLAGS_match, FLAGS_skps[i])) { |
| 193 | continue; |
| 194 | } |
| 195 | |
jvanverth | 2bb3b6d | 2016-04-08 07:24:09 -0700 | [diff] [blame] | 196 | SkString path(FLAGS_skps[i]); |
jvanverth | c265a92 | 2016-04-08 12:51:45 -0700 | [diff] [blame] | 197 | sk_sp<SKPSlide> slide(new SKPSlide(SkOSPath::Basename(path.c_str()), path)); |
jvanverth | 2bb3b6d | 2016-04-08 07:24:09 -0700 | [diff] [blame] | 198 | if (slide) { |
| 199 | fSlides.push_back(slide); |
| 200 | } |
| 201 | } else { |
| 202 | SkOSFile::Iter it(FLAGS_skps[i], ".skp"); |
jvanverth | c265a92 | 2016-04-08 12:51:45 -0700 | [diff] [blame] | 203 | SkString skpName; |
| 204 | while (it.next(&skpName)) { |
| 205 | if (SkCommandLineFlags::ShouldSkip(FLAGS_match, skpName.c_str())) { |
| 206 | continue; |
| 207 | } |
| 208 | |
| 209 | SkString path = SkOSPath::Join(FLAGS_skps[i], skpName.c_str()); |
| 210 | sk_sp<SKPSlide> slide(new SKPSlide(skpName, path)); |
jvanverth | 2bb3b6d | 2016-04-08 07:24:09 -0700 | [diff] [blame] | 211 | if (slide) { |
| 212 | fSlides.push_back(slide); |
| 213 | } |
| 214 | } |
| 215 | } |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | |
jvanverth | 3452426 | 2016-05-04 13:49:13 -0700 | [diff] [blame] | 220 | Viewer::~Viewer() { |
jvanverth | 9f37246 | 2016-04-06 06:08:59 -0700 | [diff] [blame] | 221 | fWindow->detach(); |
| 222 | delete fWindow; |
| 223 | } |
| 224 | |
brianosman | 05de216 | 2016-05-06 13:28:57 -0700 | [diff] [blame] | 225 | void Viewer::updateTitle() { |
jvanverth | 3452426 | 2016-05-04 13:49:13 -0700 | [diff] [blame] | 226 | SkString title("Viewer: "); |
jvanverth | c265a92 | 2016-04-08 12:51:45 -0700 | [diff] [blame] | 227 | title.append(fSlides[fCurrentSlide]->getName()); |
brianosman | 05de216 | 2016-05-06 13:28:57 -0700 | [diff] [blame] | 228 | if (kSRGB_SkColorProfileType == fWindow->getDisplayParams().fProfileType) { |
| 229 | title.append(" sRGB"); |
| 230 | } |
jvanverth | af236b5 | 2016-05-20 06:01:06 -0700 | [diff] [blame] | 231 | title.append(kBackendTypeStrings[fBackendType]); |
brianosman | 05de216 | 2016-05-06 13:28:57 -0700 | [diff] [blame] | 232 | fWindow->setTitle(title.c_str()); |
| 233 | } |
| 234 | |
| 235 | void Viewer::setupCurrentSlide(int previousSlide) { |
liyuqian | e5a6cd9 | 2016-05-27 08:52:52 -0700 | [diff] [blame] | 236 | if (fCurrentSlide == previousSlide) { |
| 237 | return; // no change; do nothing |
| 238 | } |
| 239 | |
liyuqian | e46e4f0 | 2016-05-20 07:32:19 -0700 | [diff] [blame] | 240 | fGesture.reset(); |
| 241 | fDefaultMatrix.reset(); |
| 242 | fDefaultMatrixInv.reset(); |
| 243 | |
| 244 | if (fWindow->supportsContentRect() && fWindow->scaleContentToFit()) { |
| 245 | const SkRect contentRect = fWindow->getContentRect(); |
| 246 | const SkISize slideSize = fSlides[fCurrentSlide]->getDimensions(); |
| 247 | const SkRect slideBounds = SkRect::MakeIWH(slideSize.width(), slideSize.height()); |
| 248 | if (contentRect.width() > 0 && contentRect.height() > 0) { |
| 249 | fDefaultMatrix.setRectToRect(slideBounds, contentRect, SkMatrix::kStart_ScaleToFit); |
liyuqian | beb1c67 | 2016-05-20 11:41:01 -0700 | [diff] [blame] | 250 | SkAssertResult(fDefaultMatrix.invert(&fDefaultMatrixInv)); |
liyuqian | e46e4f0 | 2016-05-20 07:32:19 -0700 | [diff] [blame] | 251 | } |
| 252 | } |
| 253 | |
| 254 | if (fWindow->supportsContentRect()) { |
| 255 | const SkISize slideSize = fSlides[fCurrentSlide]->getDimensions(); |
| 256 | SkRect windowRect = fWindow->getContentRect(); |
| 257 | fDefaultMatrixInv.mapRect(&windowRect); |
jvanverth | 1e305ba | 2016-06-01 09:39:15 -0700 | [diff] [blame] | 258 | fGesture.setTransLimit(SkRect::MakeWH(SkIntToScalar(slideSize.width()), |
| 259 | SkIntToScalar(slideSize.height())), |
| 260 | windowRect); |
liyuqian | e46e4f0 | 2016-05-20 07:32:19 -0700 | [diff] [blame] | 261 | } |
| 262 | |
brianosman | 05de216 | 2016-05-06 13:28:57 -0700 | [diff] [blame] | 263 | this->updateTitle(); |
liyuqian | e5a6cd9 | 2016-05-27 08:52:52 -0700 | [diff] [blame] | 264 | this->updateUIState(); |
jvanverth | c265a92 | 2016-04-08 12:51:45 -0700 | [diff] [blame] | 265 | fSlides[fCurrentSlide]->load(); |
| 266 | if (previousSlide >= 0) { |
| 267 | fSlides[previousSlide]->unload(); |
| 268 | } |
jvanverth | c265a92 | 2016-04-08 12:51:45 -0700 | [diff] [blame] | 269 | fWindow->inval(); |
| 270 | } |
| 271 | |
| 272 | #define MAX_ZOOM_LEVEL 8 |
| 273 | #define MIN_ZOOM_LEVEL -8 |
| 274 | |
jvanverth | 3452426 | 2016-05-04 13:49:13 -0700 | [diff] [blame] | 275 | void Viewer::changeZoomLevel(float delta) { |
jvanverth | c265a92 | 2016-04-08 12:51:45 -0700 | [diff] [blame] | 276 | fZoomLevel += delta; |
| 277 | if (fZoomLevel > 0) { |
| 278 | fZoomLevel = SkMinScalar(fZoomLevel, MAX_ZOOM_LEVEL); |
| 279 | fZoomScale = fZoomLevel + SK_Scalar1; |
| 280 | } else if (fZoomLevel < 0) { |
| 281 | fZoomLevel = SkMaxScalar(fZoomLevel, MIN_ZOOM_LEVEL); |
| 282 | fZoomScale = SK_Scalar1 / (SK_Scalar1 - fZoomLevel); |
| 283 | } else { |
| 284 | fZoomScale = SK_Scalar1; |
| 285 | } |
jvanverth | c265a92 | 2016-04-08 12:51:45 -0700 | [diff] [blame] | 286 | } |
| 287 | |
liyuqian | d3cdbca | 2016-05-17 12:44:20 -0700 | [diff] [blame] | 288 | SkMatrix Viewer::computeMatrix() { |
jvanverth | c265a92 | 2016-04-08 12:51:45 -0700 | [diff] [blame] | 289 | SkMatrix m; |
| 290 | m.reset(); |
| 291 | |
| 292 | if (fZoomLevel) { |
| 293 | SkPoint center; |
| 294 | //m = this->getLocalMatrix();//.invert(&m); |
| 295 | m.mapXY(fZoomCenterX, fZoomCenterY, ¢er); |
| 296 | SkScalar cx = center.fX; |
| 297 | SkScalar cy = center.fY; |
| 298 | |
| 299 | m.setTranslate(-cx, -cy); |
| 300 | m.postScale(fZoomScale, fZoomScale); |
| 301 | m.postTranslate(cx, cy); |
| 302 | } |
| 303 | |
liyuqian | d3cdbca | 2016-05-17 12:44:20 -0700 | [diff] [blame] | 304 | m.preConcat(fGesture.localM()); |
| 305 | m.preConcat(fGesture.globalM()); |
jvanverth | c265a92 | 2016-04-08 12:51:45 -0700 | [diff] [blame] | 306 | |
liyuqian | d3cdbca | 2016-05-17 12:44:20 -0700 | [diff] [blame] | 307 | return m; |
jvanverth | c265a92 | 2016-04-08 12:51:45 -0700 | [diff] [blame] | 308 | } |
| 309 | |
jvanverth | 3452426 | 2016-05-04 13:49:13 -0700 | [diff] [blame] | 310 | void Viewer::onPaint(SkCanvas* canvas) { |
jvanverth | c265a92 | 2016-04-08 12:51:45 -0700 | [diff] [blame] | 311 | int count = canvas->save(); |
djsollen | 12d62a7 | 2016-04-21 07:59:44 -0700 | [diff] [blame] | 312 | |
| 313 | if (fWindow->supportsContentRect()) { |
| 314 | SkRect contentRect = fWindow->getContentRect(); |
| 315 | canvas->clipRect(contentRect); |
| 316 | canvas->translate(contentRect.fLeft, contentRect.fTop); |
| 317 | } |
| 318 | |
| 319 | canvas->clear(SK_ColorWHITE); |
liyuqian | e46e4f0 | 2016-05-20 07:32:19 -0700 | [diff] [blame] | 320 | canvas->concat(fDefaultMatrix); |
liyuqian | d3cdbca | 2016-05-17 12:44:20 -0700 | [diff] [blame] | 321 | canvas->concat(computeMatrix()); |
jvanverth | 3d6ed3a | 2016-04-07 11:09:51 -0700 | [diff] [blame] | 322 | |
jvanverth | c265a92 | 2016-04-08 12:51:45 -0700 | [diff] [blame] | 323 | fSlides[fCurrentSlide]->draw(canvas); |
| 324 | canvas->restoreToCount(count); |
| 325 | |
| 326 | if (fDisplayStats) { |
| 327 | drawStats(canvas); |
| 328 | } |
brianosman | 622c8d5 | 2016-05-10 06:50:49 -0700 | [diff] [blame] | 329 | fCommands.drawHelp(canvas); |
jvanverth | 3d6ed3a | 2016-04-07 11:09:51 -0700 | [diff] [blame] | 330 | } |
| 331 | |
liyuqian | d3cdbca | 2016-05-17 12:44:20 -0700 | [diff] [blame] | 332 | bool Viewer::onTouch(int owner, Window::InputState state, float x, float y) { |
| 333 | void* castedOwner = reinterpret_cast<void*>(owner); |
liyuqian | e46e4f0 | 2016-05-20 07:32:19 -0700 | [diff] [blame] | 334 | SkPoint touchPoint = fDefaultMatrixInv.mapXY(x, y); |
liyuqian | d3cdbca | 2016-05-17 12:44:20 -0700 | [diff] [blame] | 335 | switch (state) { |
| 336 | case Window::kUp_InputState: { |
| 337 | fGesture.touchEnd(castedOwner); |
| 338 | break; |
| 339 | } |
| 340 | case Window::kDown_InputState: { |
liyuqian | e46e4f0 | 2016-05-20 07:32:19 -0700 | [diff] [blame] | 341 | fGesture.touchBegin(castedOwner, touchPoint.fX, touchPoint.fY); |
liyuqian | d3cdbca | 2016-05-17 12:44:20 -0700 | [diff] [blame] | 342 | break; |
| 343 | } |
| 344 | case Window::kMove_InputState: { |
liyuqian | e46e4f0 | 2016-05-20 07:32:19 -0700 | [diff] [blame] | 345 | fGesture.touchMoved(castedOwner, touchPoint.fX, touchPoint.fY); |
liyuqian | d3cdbca | 2016-05-17 12:44:20 -0700 | [diff] [blame] | 346 | break; |
| 347 | } |
| 348 | } |
| 349 | fWindow->inval(); |
| 350 | return true; |
| 351 | } |
| 352 | |
jvanverth | 3452426 | 2016-05-04 13:49:13 -0700 | [diff] [blame] | 353 | void Viewer::drawStats(SkCanvas* canvas) { |
jvanverth | 3d6ed3a | 2016-04-07 11:09:51 -0700 | [diff] [blame] | 354 | static const float kPixelPerMS = 2.0f; |
| 355 | static const int kDisplayWidth = 130; |
| 356 | static const int kDisplayHeight = 100; |
| 357 | static const int kDisplayPadding = 10; |
| 358 | static const int kGraphPadding = 3; |
| 359 | static const SkScalar kBaseMS = 1000.f / 60.f; // ms/frame to hit 60 fps |
| 360 | |
| 361 | SkISize canvasSize = canvas->getDeviceSize(); |
| 362 | SkRect rect = SkRect::MakeXYWH(SkIntToScalar(canvasSize.fWidth-kDisplayWidth-kDisplayPadding), |
| 363 | SkIntToScalar(kDisplayPadding), |
| 364 | SkIntToScalar(kDisplayWidth), SkIntToScalar(kDisplayHeight)); |
| 365 | SkPaint paint; |
| 366 | canvas->save(); |
| 367 | |
djsollen | 12d62a7 | 2016-04-21 07:59:44 -0700 | [diff] [blame] | 368 | if (fWindow->supportsContentRect()) { |
| 369 | SkRect contentRect = fWindow->getContentRect(); |
| 370 | canvas->clipRect(contentRect); |
| 371 | canvas->translate(contentRect.fLeft, contentRect.fTop); |
| 372 | } |
| 373 | |
jvanverth | 3d6ed3a | 2016-04-07 11:09:51 -0700 | [diff] [blame] | 374 | canvas->clipRect(rect); |
| 375 | paint.setColor(SK_ColorBLACK); |
| 376 | canvas->drawRect(rect, paint); |
| 377 | // draw the 16ms line |
| 378 | paint.setColor(SK_ColorLTGRAY); |
| 379 | canvas->drawLine(rect.fLeft, rect.fBottom - kBaseMS*kPixelPerMS, |
| 380 | rect.fRight, rect.fBottom - kBaseMS*kPixelPerMS, paint); |
| 381 | paint.setColor(SK_ColorRED); |
| 382 | paint.setStyle(SkPaint::kStroke_Style); |
| 383 | canvas->drawRect(rect, paint); |
| 384 | |
| 385 | int x = SkScalarTruncToInt(rect.fLeft) + kGraphPadding; |
| 386 | const int xStep = 2; |
| 387 | const int startY = SkScalarTruncToInt(rect.fBottom); |
| 388 | int i = fCurrentMeasurement; |
| 389 | do { |
| 390 | int endY = startY - (int)(fMeasurements[i] * kPixelPerMS + 0.5); // round to nearest value |
| 391 | canvas->drawLine(SkIntToScalar(x), SkIntToScalar(startY), |
| 392 | SkIntToScalar(x), SkIntToScalar(endY), paint); |
| 393 | i++; |
| 394 | i &= (kMeasurementCount - 1); // fast mod |
| 395 | x += xStep; |
| 396 | } while (i != fCurrentMeasurement); |
jvanverth | 9f37246 | 2016-04-06 06:08:59 -0700 | [diff] [blame] | 397 | |
| 398 | canvas->restore(); |
| 399 | } |
| 400 | |
jvanverth | 3452426 | 2016-05-04 13:49:13 -0700 | [diff] [blame] | 401 | void Viewer::onIdle(double ms) { |
jvanverth | 3d6ed3a | 2016-04-07 11:09:51 -0700 | [diff] [blame] | 402 | // Record measurements |
| 403 | fMeasurements[fCurrentMeasurement++] = ms; |
| 404 | fCurrentMeasurement &= (kMeasurementCount - 1); // fast mod |
| 405 | SkASSERT(fCurrentMeasurement < kMeasurementCount); |
| 406 | |
jvanverth | c265a92 | 2016-04-08 12:51:45 -0700 | [diff] [blame] | 407 | fAnimTimer.updateTime(); |
jvanverth | 9d5e47f | 2016-04-26 08:01:33 -0700 | [diff] [blame] | 408 | if (fSlides[fCurrentSlide]->animate(fAnimTimer) || fDisplayStats) { |
jvanverth | c265a92 | 2016-04-08 12:51:45 -0700 | [diff] [blame] | 409 | fWindow->inval(); |
| 410 | } |
jvanverth | 9f37246 | 2016-04-06 06:08:59 -0700 | [diff] [blame] | 411 | } |
liyuqian | e5a6cd9 | 2016-05-27 08:52:52 -0700 | [diff] [blame] | 412 | |
| 413 | void Viewer::updateUIState() { |
| 414 | Json::Value slideState(Json::objectValue); |
| 415 | slideState[kName] = kSlideStateName; |
| 416 | slideState[kValue] = fSlides[fCurrentSlide]->getName().c_str(); |
| 417 | Json::Value allSlideNames(Json::arrayValue); |
| 418 | for(auto slide : fSlides) { |
| 419 | allSlideNames.append(Json::Value(slide->getName().c_str())); |
| 420 | } |
| 421 | slideState[kOptions] = allSlideNames; |
| 422 | |
| 423 | // This state is currently a demo for the one without options. |
| 424 | // We will be able to change the backend too. |
| 425 | Json::Value backendState(Json::objectValue); |
| 426 | backendState[kName] = kBackendStateName; |
liyuqian | 6cb7025 | 2016-06-02 12:16:25 -0700 | [diff] [blame^] | 427 | backendState[kValue] = kBackendTypeStrings[fBackendType]; |
liyuqian | e5a6cd9 | 2016-05-27 08:52:52 -0700 | [diff] [blame] | 428 | backendState[kOptions] = Json::Value(Json::arrayValue); |
liyuqian | 6cb7025 | 2016-06-02 12:16:25 -0700 | [diff] [blame^] | 429 | for(auto str : kBackendTypeStrings) { |
| 430 | backendState[kOptions].append(Json::Value(str)); |
| 431 | } |
liyuqian | e5a6cd9 | 2016-05-27 08:52:52 -0700 | [diff] [blame] | 432 | |
| 433 | Json::Value state(Json::arrayValue); |
| 434 | state.append(slideState); |
| 435 | state.append(backendState); |
| 436 | |
| 437 | fWindow->setUIState(state); |
| 438 | } |
| 439 | |
| 440 | void Viewer::onUIStateChanged(const SkString& stateName, const SkString& stateValue) { |
liyuqian | 6cb7025 | 2016-06-02 12:16:25 -0700 | [diff] [blame^] | 441 | // For those who will add more features to handle the state change in this function: |
| 442 | // After the change, please call updateUIState no notify the frontend (e.g., Android app). |
| 443 | // For example, after slide change, updateUIState is called inside setupCurrentSlide; |
| 444 | // after backend change, updateUIState is called in this function. |
liyuqian | e5a6cd9 | 2016-05-27 08:52:52 -0700 | [diff] [blame] | 445 | if (stateName.equals(kSlideStateName)) { |
| 446 | int previousSlide = fCurrentSlide; |
| 447 | fCurrentSlide = 0; |
| 448 | for(auto slide : fSlides) { |
| 449 | if (slide->getName().equals(stateValue)) { |
| 450 | setupCurrentSlide(previousSlide); |
| 451 | break; |
| 452 | } |
| 453 | fCurrentSlide++; |
| 454 | } |
| 455 | if (fCurrentSlide >= fSlides.count()) { |
| 456 | fCurrentSlide = previousSlide; |
| 457 | SkDebugf("Slide not found: %s", stateValue.c_str()); |
| 458 | } |
liyuqian | 6cb7025 | 2016-06-02 12:16:25 -0700 | [diff] [blame^] | 459 | } else if (stateName.equals(kBackendStateName)) { |
| 460 | for (int i = 0; i < sk_app::Window::kBackendTypeCount; i++) { |
| 461 | if (stateValue.equals(kBackendTypeStrings[i])) { |
| 462 | if (fBackendType != i) { |
| 463 | fBackendType = (sk_app::Window::BackendType)i; |
| 464 | fWindow->detach(); |
| 465 | fWindow->attach(fBackendType, DisplayParams()); |
| 466 | fWindow->inval(); |
| 467 | updateTitle(); |
| 468 | updateUIState(); |
| 469 | } |
| 470 | break; |
| 471 | } |
| 472 | } |
liyuqian | e5a6cd9 | 2016-05-27 08:52:52 -0700 | [diff] [blame] | 473 | } else { |
| 474 | SkDebugf("Unknown stateName: %s", stateName.c_str()); |
| 475 | } |
| 476 | } |