SkottieSlide.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. * Copyright 2017 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. #include "tools/viewer/SkottieSlide.h"
  8. #if defined(SK_ENABLE_SKOTTIE)
  9. #include "include/core/SkCanvas.h"
  10. #include "include/core/SkFont.h"
  11. #include "modules/skottie/include/Skottie.h"
  12. #include "modules/skottie/utils/SkottieUtils.h"
  13. #include "src/utils/SkOSPath.h"
  14. #include "tools/timer/TimeUtils.h"
  15. #include <cmath>
  16. static void draw_stats_box(SkCanvas* canvas, const skottie::Animation::Builder::Stats& stats) {
  17. static constexpr SkRect kR = { 10, 10, 280, 120 };
  18. static constexpr SkScalar kTextSize = 20;
  19. SkPaint paint;
  20. paint.setAntiAlias(true);
  21. paint.setColor(0xffeeeeee);
  22. SkFont font(nullptr, kTextSize);
  23. canvas->drawRect(kR, paint);
  24. paint.setColor(SK_ColorBLACK);
  25. const auto json_size = SkStringPrintf("Json size: %lu bytes",
  26. stats.fJsonSize);
  27. canvas->drawString(json_size, kR.x() + 10, kR.y() + kTextSize * 1, font, paint);
  28. const auto animator_count = SkStringPrintf("Animator count: %lu",
  29. stats.fAnimatorCount);
  30. canvas->drawString(animator_count, kR.x() + 10, kR.y() + kTextSize * 2, font, paint);
  31. const auto json_parse_time = SkStringPrintf("Json parse time: %.3f ms",
  32. stats.fJsonParseTimeMS);
  33. canvas->drawString(json_parse_time, kR.x() + 10, kR.y() + kTextSize * 3, font, paint);
  34. const auto scene_parse_time = SkStringPrintf("Scene build time: %.3f ms",
  35. stats.fSceneParseTimeMS);
  36. canvas->drawString(scene_parse_time, kR.x() + 10, kR.y() + kTextSize * 4, font, paint);
  37. const auto total_load_time = SkStringPrintf("Total load time: %.3f ms",
  38. stats.fTotalLoadTimeMS);
  39. canvas->drawString(total_load_time, kR.x() + 10, kR.y() + kTextSize * 5, font, paint);
  40. paint.setStyle(SkPaint::kStroke_Style);
  41. canvas->drawRect(kR, paint);
  42. }
  43. SkottieSlide::SkottieSlide(const SkString& name, const SkString& path)
  44. : fPath(path) {
  45. fName = name;
  46. }
  47. void SkottieSlide::load(SkScalar w, SkScalar h) {
  48. class Logger final : public skottie::Logger {
  49. public:
  50. struct LogEntry {
  51. SkString fMessage,
  52. fJSON;
  53. };
  54. void log(skottie::Logger::Level lvl, const char message[], const char json[]) override {
  55. auto& log = lvl == skottie::Logger::Level::kError ? fErrors : fWarnings;
  56. log.push_back({ SkString(message), json ? SkString(json) : SkString() });
  57. }
  58. void report() const {
  59. SkDebugf("Animation loaded with %lu error%s, %lu warning%s.\n",
  60. fErrors.size(), fErrors.size() == 1 ? "" : "s",
  61. fWarnings.size(), fWarnings.size() == 1 ? "" : "s");
  62. const auto& show = [](const LogEntry& log, const char prefix[]) {
  63. SkDebugf("%s%s", prefix, log.fMessage.c_str());
  64. if (!log.fJSON.isEmpty())
  65. SkDebugf(" : %s", log.fJSON.c_str());
  66. SkDebugf("\n");
  67. };
  68. for (const auto& err : fErrors) show(err, " !! ");
  69. for (const auto& wrn : fWarnings) show(wrn, " ?? ");
  70. }
  71. private:
  72. std::vector<LogEntry> fErrors,
  73. fWarnings;
  74. };
  75. auto logger = sk_make_sp<Logger>();
  76. skottie::Animation::Builder builder;
  77. fAnimation = builder
  78. .setLogger(logger)
  79. .setResourceProvider(
  80. skottie_utils::FileResourceProvider::Make(SkOSPath::Dirname(fPath.c_str())))
  81. .makeFromFile(fPath.c_str());
  82. fAnimationStats = builder.getStats();
  83. fWinSize = SkSize::Make(w, h);
  84. fTimeBase = 0; // force a time reset
  85. if (fAnimation) {
  86. SkDebugf("Loaded Bodymovin animation v: %s, size: [%f %f]\n",
  87. fAnimation->version().c_str(),
  88. fAnimation->size().width(),
  89. fAnimation->size().height());
  90. logger->report();
  91. } else {
  92. SkDebugf("failed to load Bodymovin animation: %s\n", fPath.c_str());
  93. }
  94. }
  95. void SkottieSlide::unload() {
  96. fAnimation.reset();
  97. }
  98. SkISize SkottieSlide::getDimensions() const {
  99. // We always scale to fill the window.
  100. return fWinSize.toCeil();
  101. }
  102. void SkottieSlide::draw(SkCanvas* canvas) {
  103. if (fAnimation) {
  104. SkAutoCanvasRestore acr(canvas, true);
  105. const auto dstR = SkRect::MakeSize(fWinSize);
  106. fAnimation->render(canvas, &dstR);
  107. if (fShowAnimationStats) {
  108. draw_stats_box(canvas, fAnimationStats);
  109. }
  110. if (fShowAnimationInval) {
  111. const auto t = SkMatrix::MakeRectToRect(SkRect::MakeSize(fAnimation->size()),
  112. dstR,
  113. SkMatrix::kCenter_ScaleToFit);
  114. SkPaint fill, stroke;
  115. fill.setAntiAlias(true);
  116. fill.setColor(0x40ff0000);
  117. stroke.setAntiAlias(true);
  118. stroke.setColor(0xffff0000);
  119. stroke.setStyle(SkPaint::kStroke_Style);
  120. for (const auto& r : fInvalController) {
  121. SkRect bounds;
  122. t.mapRect(&bounds, r);
  123. canvas->drawRect(bounds, fill);
  124. canvas->drawRect(bounds, stroke);
  125. }
  126. }
  127. }
  128. }
  129. bool SkottieSlide::animate(double nanos) {
  130. SkMSec msec = TimeUtils::NanosToMSec(nanos);
  131. if (fTimeBase == 0) {
  132. // Reset the animation time.
  133. fTimeBase = msec;
  134. }
  135. if (fAnimation) {
  136. fInvalController.reset();
  137. const auto t = msec - fTimeBase;
  138. const auto d = fAnimation->duration() * 1000;
  139. fAnimation->seek(std::fmod(t, d) / d, &fInvalController);
  140. }
  141. return true;
  142. }
  143. bool SkottieSlide::onChar(SkUnichar c) {
  144. switch (c) {
  145. case 'I':
  146. fShowAnimationStats = !fShowAnimationStats;
  147. break;
  148. default:
  149. break;
  150. }
  151. return INHERITED::onChar(c);
  152. }
  153. bool SkottieSlide::onMouse(SkScalar x, SkScalar y, InputState state, ModifierKey) {
  154. switch (state) {
  155. case InputState::kUp:
  156. fShowAnimationInval = !fShowAnimationInval;
  157. fShowAnimationStats = !fShowAnimationStats;
  158. break;
  159. default:
  160. break;
  161. }
  162. return false;
  163. }
  164. #endif // SK_ENABLE_SKOTTIE