2019-09-09 21:03:38 +00:00
|
|
|
//Copyright 2019 Google LLC.
|
|
|
|
//Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
#include "experimental/skottie_ios/SkottieMtkView.h"
|
|
|
|
|
|
|
|
#include "include/core/SkCanvas.h"
|
|
|
|
#include "include/core/SkPaint.h"
|
|
|
|
#include "include/core/SkSurface.h"
|
|
|
|
#include "include/core/SkTime.h"
|
|
|
|
|
|
|
|
#include "modules/skottie/include/Skottie.h"
|
|
|
|
|
|
|
|
#include "experimental/skottie_ios/SkMetalViewBridge.h"
|
|
|
|
|
|
|
|
@implementation SkottieMtkView {
|
|
|
|
sk_sp<skottie::Animation> fAnimation; // owner
|
|
|
|
CGSize fSize;
|
2019-09-26 18:29:51 +00:00
|
|
|
double fStartTime; // used when running
|
|
|
|
float fAnimationMoment; // when paused.
|
2019-09-09 21:03:38 +00:00
|
|
|
SkMatrix fMatrix;
|
2019-09-26 18:29:51 +00:00
|
|
|
SkSize fAnimationSize;
|
2019-09-09 21:03:38 +00:00
|
|
|
bool fPaused;
|
|
|
|
}
|
|
|
|
|
|
|
|
-(void)dealloc {
|
|
|
|
fAnimation = nullptr;
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)drawRect:(CGRect)rect {
|
|
|
|
[super drawRect:rect];
|
|
|
|
// TODO(halcanary): Use the rect and the InvalidationController to speed up rendering.
|
|
|
|
if (!fAnimation || ![[self currentDrawable] texture] || ![self grContext]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
CGSize size = [self drawableSize];
|
|
|
|
if (size.width != fSize.width || size.height != fSize.height) {
|
2019-09-26 18:29:51 +00:00
|
|
|
// Cache the current matrix; change only if size changes.
|
|
|
|
if (fAnimationSize.width() > 0 && fAnimationSize.height() > 0) {
|
|
|
|
float scale = std::min(size.width / fAnimationSize.width(),
|
|
|
|
size.height / fAnimationSize.height());
|
|
|
|
fMatrix.setScaleTranslate(
|
|
|
|
scale, scale,
|
|
|
|
((float)size.width - fAnimationSize.width() * scale) * 0.5f,
|
|
|
|
((float)size.height - fAnimationSize.height() * scale) * 0.5f);
|
2019-09-09 21:03:38 +00:00
|
|
|
} else {
|
|
|
|
fMatrix = SkMatrix();
|
|
|
|
}
|
|
|
|
fSize = size;
|
|
|
|
}
|
|
|
|
SkPaint whitePaint(SkColors::kWhite);
|
|
|
|
if (!fPaused) {
|
2019-09-26 18:29:51 +00:00
|
|
|
fAnimation->seekFrameTime([self currentTime], nullptr);
|
2019-09-09 21:03:38 +00:00
|
|
|
}
|
|
|
|
sk_sp<SkSurface> surface = SkMtkViewToSurface(self, [self grContext]);
|
|
|
|
if (!surface) {
|
|
|
|
NSLog(@"error: no sksurface");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
SkCanvas* canvas = surface->getCanvas();
|
|
|
|
canvas->concat(fMatrix);
|
2019-09-26 18:29:51 +00:00
|
|
|
canvas->drawRect(SkRect{0, 0, fAnimationSize.width(), fAnimationSize.height()}, whitePaint);
|
2019-09-09 21:03:38 +00:00
|
|
|
fAnimation->render(canvas);
|
|
|
|
surface->flush();
|
|
|
|
surface = nullptr;
|
|
|
|
[[self currentDrawable] present];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)loadAnimation:(NSData*) data {
|
|
|
|
skottie::Animation::Builder builder;
|
|
|
|
fAnimation = builder.make((const char*)[data bytes], (size_t)[data length]);
|
2019-09-26 18:29:51 +00:00
|
|
|
fStartTime = SkTime::GetNSecs();
|
|
|
|
fAnimationMoment = 0;
|
2019-09-09 21:03:38 +00:00
|
|
|
fSize = {0, 0};
|
2019-09-26 18:29:51 +00:00
|
|
|
fAnimationSize = fAnimation ? fAnimation->size() : SkSize{0, 0};
|
2019-09-09 21:03:38 +00:00
|
|
|
return fAnimation != nullptr;
|
|
|
|
}
|
|
|
|
|
2019-09-26 18:29:51 +00:00
|
|
|
- (float)animationDurationSeconds {
|
|
|
|
return fAnimation ? fAnimation->duration() : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (float)currentTime {
|
|
|
|
if (!fAnimation) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (fPaused) {
|
|
|
|
return fAnimationMoment;
|
|
|
|
}
|
|
|
|
return std::fmod(1e-9 * (SkTime::GetNSecs() - fStartTime), fAnimation->duration());
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)seek:(float)seconds {
|
2019-09-09 21:03:38 +00:00
|
|
|
if (fAnimation) {
|
2019-09-26 18:29:51 +00:00
|
|
|
if (fPaused) {
|
|
|
|
fAnimationMoment = std::fmod(seconds, fAnimation->duration());
|
|
|
|
fAnimation->seekFrameTime(fAnimationMoment);
|
|
|
|
} else {
|
|
|
|
fStartTime = SkTime::GetNSecs() - 1e9 * seconds;
|
|
|
|
}
|
2019-09-09 21:03:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-26 18:29:51 +00:00
|
|
|
- (CGSize)size { return {(CGFloat)fAnimationSize.width(), (CGFloat)fAnimationSize.height()}; }
|
|
|
|
|
2019-09-09 21:03:38 +00:00
|
|
|
- (BOOL)togglePaused {
|
2019-09-26 18:29:51 +00:00
|
|
|
if (fPaused) {
|
|
|
|
fStartTime = SkTime::GetNSecs() - 1e9 * fAnimationMoment;
|
|
|
|
} else {
|
|
|
|
fAnimationMoment = [self currentTime];
|
2019-09-09 21:03:38 +00:00
|
|
|
}
|
2019-09-26 18:29:51 +00:00
|
|
|
fPaused = !fPaused;
|
2019-09-09 21:03:38 +00:00
|
|
|
return fPaused;
|
|
|
|
}
|
|
|
|
@end
|