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

#include "experimental/ngatoy/Fake.h"

#include "experimental/ngatoy/Cmds.h"
#include "experimental/ngatoy/SortKey.h"

#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"

//-------------------------------------------------------------------------------------------------
void FakeMCBlob::MCState::addRect(SkIRect r, sk_sp<ClipCmd> clipCmd) {
    fRects.push_back(r.makeOffset(fTrans.fX, fTrans.fY));
    fCmds.push_back(std::move(clipCmd));
    fCached = nullptr;
}

void FakeMCBlob::MCState::apply(SkCanvas* canvas) const {
    canvas->save();

    for (auto c : fRects) {
        canvas->clipIRect(c);
    }

    canvas->translate(fTrans.fX, fTrans.fY);
}

void FakeMCBlob::MCState::apply(FakeCanvas* canvas) const {
    canvas->save();

    for (auto c : fRects) {
        canvas->clipRect(ID::Invalid(), c);
    }

    canvas->translate(fTrans);
}

//-------------------------------------------------------------------------------------------------
// Linearly blend between c0 & c1:
//      (t == 0) -> c0
//      (t == 1) -> c1
static SkColor blend(float t, SkColor c0, SkColor c1) {
    SkASSERT(t >= 0.0f && t <= 1.0f);

    SkColor4f top = SkColor4f::FromColor(c0);
    SkColor4f bot = SkColor4f::FromColor(c1);

    SkColor4f result = {
        t * bot.fR + (1.0f - t) * top.fR,
        t * bot.fG + (1.0f - t) * top.fG,
        t * bot.fB + (1.0f - t) * top.fB,
        t * bot.fA + (1.0f - t) * top.fA
    };
    return result.toSkColor();
}

int FakePaint::toID() const {
    switch (fType) {
        case Type::kNormal: return kSolidMat;
        case Type::kLinear: return kLinearMat;
        case Type::kRadial: return kRadialMat;
    }
    SkUNREACHABLE;
}

SkColor FakePaint::evalColor(int x, int y) const {
    switch (fType) {
        case Type::kNormal: return fColor0;
        case Type::kLinear: {
            float t = SK_ScalarRoot2Over2 * x + SK_ScalarRoot2Over2 * y;
            t /= SK_ScalarSqrt2 * 256.0f;
            return blend(t, fColor0, fColor1);
        }
        case Type::kRadial: {
            x -= 128;
            y -= 128;
            float dist = sqrt(x*x + y*y) / 128.0f;
            if (dist > 1.0f) {
                return fColor0;
            } else {
                return blend(dist, fColor0, fColor1);
            }
        }
    }
    SkUNREACHABLE;
}

//-------------------------------------------------------------------------------------------------
void FakeDevice::save() {
    fTracker.push();
}

void FakeDevice::drawRect(ID id, PaintersOrder paintersOrder, SkIRect r, FakePaint p) {
    sk_sp<FakeMCBlob> state = fTracker.snapState();
    SkASSERT(state);

    sk_sp<Cmd> tmp = sk_make_sp<RectCmd>(id, paintersOrder, r, p, std::move(state));

    fSortedCmds.push_back(std::move(tmp));
}

void FakeDevice::clipRect(ID id, PaintersOrder paintersOrder, SkIRect r) {
    sk_sp<ClipCmd> tmp = sk_make_sp<ClipCmd>(id, paintersOrder, r);

    fTracker.clipRect(r, std::move(tmp));
}

void FakeDevice::restore() {
    fTracker.pop();
}

void FakeDevice::finalize() {
    SkASSERT(!fFinalized);
    fFinalized = true;

    this->sort();
    for (const sk_sp<Cmd>& c : fSortedCmds) {
        c->rasterize(fZBuffer, &fBM);
    }
}

void FakeDevice::getOrder(std::vector<ID>* ops) const {
    SkASSERT(fFinalized);

    for (const sk_sp<Cmd>& c : fSortedCmds) {
        ops->push_back(c->id());
    }
}

void FakeDevice::sort() {
    // In general we want:
    //  opaque draws to occur front to back (i.e., in reverse painter's order) while minimizing
    //        state changes due to materials
    //  transparent draws to occur back to front (i.e., in painter's order)
    //
    // In both scenarios we would like to batch as much as possible.
    std::sort(fSortedCmds.begin(), fSortedCmds.end(),
              [](const sk_sp<Cmd>& a, const sk_sp<Cmd>& b) {
                    return a->getKey() < b->getKey();
                });
}

//-------------------------------------------------------------------------------------------------
void FakeCanvas::drawRect(ID id, SkIRect r, FakePaint p) {
    SkASSERT(!fFinalized);

    fDeviceStack.back()->drawRect(id, this->nextPaintersOrder(), r, p);
}

void FakeCanvas::clipRect(ID id, SkIRect r) {
    SkASSERT(!fFinalized);

    fDeviceStack.back()->clipRect(id, this->nextPaintersOrder(), r);
}

void FakeCanvas::finalize() {
    SkASSERT(!fFinalized);
    fFinalized = true;

    for (auto& d : fDeviceStack) {
        d->finalize();
    }
}

std::vector<ID> FakeCanvas::getOrder() const {
    SkASSERT(fFinalized);

    std::vector<ID> ops;

    for (auto& d : fDeviceStack) {
        d->getOrder(&ops);
    }

    return ops;
}
