/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SKPAnimationBench.h"
#include "SkCommandLineFlags.h"
#include "SkMultiPictureDraw.h"
#include "SkSurface.h"

SKPAnimationBench::SKPAnimationBench(const char* name, const SkPicture* pic, const SkIRect& clip,
                                     Animation* animation, bool doLooping)
    : INHERITED(name, pic, clip, 1.0, false, doLooping)
    , fAnimation(SkRef(animation)) {
    fUniqueName.printf("%s_%s", name, fAnimation->getTag());
}

const char* SKPAnimationBench::onGetUniqueName() {
    return fUniqueName.c_str();
}

void SKPAnimationBench::onPerCanvasPreDraw(SkCanvas* canvas) {
    INHERITED::onPerCanvasPreDraw(canvas);
    fDevBounds = canvas->getDeviceClipBounds();
    SkAssertResult(!fDevBounds.isEmpty());
    fAnimationTimer.start();
}

void SKPAnimationBench::drawPicture() {
    fAnimationTimer.end();

    for (int j = 0; j < this->tileRects().count(); ++j) {
        SkMatrix trans = SkMatrix::MakeTrans(-1.f * this->tileRects()[j].fLeft,
                                             -1.f * this->tileRects()[j].fTop);
        fAnimation->preConcatFrameMatrix(fAnimationTimer.fWall, fDevBounds, &trans);
        this->surfaces()[j]->getCanvas()->drawPicture(this->picture(), &trans, nullptr);
    }

    for (int j = 0; j < this->tileRects().count(); ++j) {
       this->surfaces()[j]->getCanvas()->flush();
    }
}

class ZoomAnimation : public SKPAnimationBench::Animation {
public:
    ZoomAnimation(SkScalar zoomMax, double zoomPeriodMs)
        : fZoomMax(zoomMax)
        , fZoomPeriodMs(zoomPeriodMs) {
    }

    virtual const char* getTag() { return "zoom"; }

    virtual void preConcatFrameMatrix(double animationTimeMs, const SkIRect& devBounds,
                                      SkMatrix* drawMatrix) {
        double t = fmod(animationTimeMs / fZoomPeriodMs, 1.0); // t is in [0, 1).
        t = fabs(2 * t - 1); // Make t ping-pong between 0 and 1
        SkScalar zoom = static_cast<SkScalar>(pow(fZoomMax, t));

        SkPoint center = SkPoint::Make((devBounds.fLeft + devBounds.fRight) / 2.0f,
                                       (devBounds.fTop + devBounds.fBottom) / 2.0f);
        drawMatrix->preTranslate(center.fX, center.fY);
        drawMatrix->preScale(zoom, zoom);
        drawMatrix->preTranslate(-center.fX, -center.fY);
    }

private:
    double   fZoomMax;
    double   fZoomPeriodMs;
};

SKPAnimationBench::Animation* SKPAnimationBench::CreateZoomAnimation(SkScalar zoomMax,
                                                                     double zoomPeriodMs) {
    return new ZoomAnimation(zoomMax, zoomPeriodMs);
}