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

#ifndef SortKey_DEFINED
#define SortKey_DEFINED

#include "include/core/SkTypes.h"

// These are the material IDs that are stored in the sort key for each class of material
constexpr int kInvalidMat = 0;
constexpr int kSolidMat   = 1;
constexpr int kLinearMat  = 2;
constexpr int kRadialMat  = 3;

class SortKey {
public:
    // field:  |  transparent  | clipID  | depth   |  material  |
    // bits:   |      1        |   8     |  4      |     4      |
    // Note: the depth and material fields are swapped when the key is opaque and the depth's
    // order is reversed. This forces all opaque draws with the be sorted by material first
    // and then front to back. Transparent draws will continue to be sorted back to front.
    static const uint32_t kMaterialShift = 0;
    static const uint32_t kNumMaterialBits = 4;
    static const uint32_t kMaterialMask = (0x1 << kNumMaterialBits) - 1;

    // The pseudo-Z generated by the draw calls is just a proxy for painter's order.
    // The "depth" value stored here is a munged version of the pseudo-Z to get the sorting
    // correct.
    // For opaque objects the pseudo-Z is reversed so opaque objects are drawn front to back (i.e.,
    // reverse painter's order).
    // For transparent objects the pseudo-Z is untouched but the transparent bit is set on the
    // key so transparent object will always be drawn after the opaque objects and in painter's
    // order.
    static const uint32_t kDepthShift = kNumMaterialBits;
    static const uint32_t kNumDepthBits = 4;
    static const uint32_t kDepthMask = (0x1 << kNumDepthBits) - 1;
    static const uint32_t kMaxDepth = kDepthMask;

    static const uint32_t kClipShift = kNumMaterialBits + kNumDepthBits;
    static const uint32_t kNumClipBits = 8;
    static const uint32_t kClipMask = (0x01 << kNumClipBits) - 1;
    static const uint32_t kMaxClipID = kClipMask;

    static const uint32_t kTransparentShift = kNumMaterialBits + kNumDepthBits + kNumClipBits;
    static const uint32_t kNumTransparentBits = 1;
    static const uint32_t kTransparentMask = (0x1 << kNumTransparentBits) - 1;

    // TODO: make it clearer that we're initializing the default depth to be 0 here (since the
    // default key is opaque, its sense is flipped)
    SortKey() : fKey((kMaxDepth - 1) << kMaterialShift) {}
    explicit SortKey(bool transparent, uint32_t clipID, uint32_t depth, uint32_t material) {
        SkASSERT(clipID != 0 && depth != 0 /* && material != 0*/);
        SkASSERT(!(clipID & ~kClipMask));
        SkASSERT(!(depth & ~kDepthMask));
        SkASSERT(!(material & ~kMaterialMask));

        // TODO: better encapsulate the reversal of the depth & material when the key is opaque
        if (transparent) {
            fKey = (0x1 << kTransparentShift) |
                   (clipID & kClipMask) << kClipShift |
                   (depth & kDepthMask) << kDepthShift |
                   (material & kMaterialMask) << kMaterialShift;
        } else {
            SkASSERT(kNumDepthBits == kNumMaterialBits);

            uint32_t munged;
            // We want the opaque draws to be sorted front to back
            munged = kMaxDepth - depth - 1;
            SkASSERT(!(munged & ~kDepthMask));

            fKey = (clipID & kClipMask) << kClipShift |
                   (munged & kDepthMask) << kMaterialShift |
                   (material & kMaterialMask) << kDepthShift;
        }
    }

    bool transparent() const {
        return (fKey >> kTransparentShift) & kTransparentMask;
    }

    uint32_t clipID() const {
        return (fKey >> kClipShift) & kClipMask;
    }

    uint32_t depth() const {
        if (this->transparent()) {
            return (fKey >> kDepthShift) & kDepthMask;
        }

        // TODO: foo
        uint32_t tmp = (fKey >> kMaterialShift) & kDepthMask;
        return (kMaxDepth - tmp) - 1;
    }

    uint32_t material() const {
        // TODO: better encapsulate the reversal of the depth & material when the key is opaque
        if (this->transparent()) {
            return (fKey >> kMaterialShift) & kMaterialMask;
        } else {
            return (fKey >> kDepthShift) & kMaterialMask;
        }
    }

    void dump() const {
        SkDebugf("transparent: %d depth: %d mat: %d\n",
                 this->transparent(),
                 this->depth(),
                 this->material());
    }

    bool operator>(const SortKey& other) const { return fKey > other.fKey; }
    bool operator<(const SortKey& other) const { return fKey < other.fKey; }

private:
    uint64_t fKey;
};

#endif // Key_DEFINED
