/*
 * Copyright (C) 2020-2021 Aloysius Indrayanto
 *
 * This file is part of the eCxx library, see LICENSE file for the license details.
 */


#ifndef ECXX_CTL_GFX_COLOR_BUFFER_LAYOUT_POLICY_PLAIN_ALT_H
#define ECXX_CTL_GFX_COLOR_BUFFER_LAYOUT_POLICY_PLAIN_ALT_H


namespace eCxx {


//
// Color buffer layout policy constants - plain with alternating pixel direction
//
namespace CBP {

    struct AltRowMajor;
    struct AltRowMajorRX;
    struct AltRowMajorRY;
    struct AltRowMajorRXY;

    ////////////////////////////////////////////////////////////////////////////////////////////////////

    struct AltColMajor;
    struct AltColMajorRX;
    struct AltColMajorRY;
    struct AltColMajorRXY;

    ////////////////////////////////////////////////////////////////////////////////////////////////////

    // These alternative names are created based on the effect that would be achieved if the
    // visual pixel flow/movement were normal

    using AltStandardLayout            = AltRowMajor;
    using AltHorizontalFlip            = AltRowMajorRX;
    using AltVerticalFlip              = AltRowMajorRY;
    using AltBothFlip                  = AltRowMajorRXY;

    using AltRotate90CW                = AltColMajorRY;
    using AltRotate90CWHorizontalFlip  = AltColMajor;
    using AltRotate90CWVerticalFlip    = AltColMajorRXY;
    using AltRotate90CWBothFlip        = AltColMajorRX;

    using AltRotate180CW               = AltRowMajorRXY;
    using AltRotate180CWHorizontalFlip = AltRowMajorRY;
    using AltRotate180CWVerticalFlip   = AltRowMajorRX;
    using AltRotate180CWBothFlip       = AltRowMajor;

    using AltRotate270CW               = AltColMajorRX;
    using AltRotate270CWHorizontalFlip = AltColMajorRXY;
    using AltRotate270CWVerticalFlip   = AltColMajor;
    using AltRotate270CWBothFlip       = AltColMajorRY;

} // namespace CBP


//
// Specialization of color buffer layout element size exchanger to swap the XSize and YSize
//
template <CBP::SUInt XSizeN, CBP::SUInt YSizeN>
struct ColorBufferLayoutElementSizeExchanger<XSizeN, YSizeN, CBP::AltColMajor   > : internal::CBEZSwap<XSizeN, YSizeN> {};

template <CBP::SUInt XSizeN, CBP::SUInt YSizeN>
struct ColorBufferLayoutElementSizeExchanger<XSizeN, YSizeN, CBP::AltColMajorRX > : internal::CBEZSwap<XSizeN, YSizeN> {};

template <CBP::SUInt XSizeN, CBP::SUInt YSizeN>
struct ColorBufferLayoutElementSizeExchanger<XSizeN, YSizeN, CBP::AltColMajorRY > : internal::CBEZSwap<XSizeN, YSizeN> {};

template <CBP::SUInt XSizeN, CBP::SUInt YSizeN>
struct ColorBufferLayoutElementSizeExchanger<XSizeN, YSizeN, CBP::AltColMajorRXY> : internal::CBEZSwap<XSizeN, YSizeN> {};


//
// Implementation of color buffer layout policy structures - plain with alternating pixel direction
//
// NOTE : # The policies defined here ignore BlockXSizeN
//        # The policies defined here ignore BlockYSizeN
//        # The policies defined here ignore InterYSizeN
//
template <CBP::SUInt XSizeN, CBP::SUInt YSizeN, CBP::SUInt BlockXSizeN, CBP::SUInt BlockYSizeN, CBP::SUInt InterYSizeN>
struct ColorBufferLayoutPolicy<XSizeN, YSizeN, BlockXSizeN, BlockYSizeN, InterYSizeN, CBP::AltRowMajor> : public Uninstantiable {
    /*
     * Visual and hardware pixel flow/movement example for 4x4
     *
     * Visual             Hardware
     * |  0  1  2  3 |    |  0  1  2  3 |
     * |  4  5  6  7 | -> |  7  6  5  4 |
     * |  8  9 10 11 |    |  8  9 10 11 |
     * | 12 13 14 15 |    | 15 14 13 12 |
     *
     * Hardware pixel flow/movement example for 4x4 (pixel and memory address dump)
     *
     * | (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address |
     * | (0,0) (1,0) (2,0) (3,0) |   |  0  1  2  3 |
     * | (3,1) (2,1) (1,1) (0,1) |   |  7  6  5  4 |
     * | (0,2) (1,2) (2,2) (3,2) |   |  8  9 10 11 |
     * | (3,3) (2,3) (1,3) (0,3) |   | 15 14 13 12 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    { return (y & 1) ? ( (XSizeN - 1 - x) + y * XSizeN ) : (x + y * XSizeN); }
};


template <CBP::SUInt XSizeN, CBP::SUInt YSizeN, CBP::SUInt BlockXSizeN, CBP::SUInt BlockYSizeN, CBP::SUInt InterYSizeN>
struct ColorBufferLayoutPolicy<XSizeN, YSizeN, BlockXSizeN, BlockYSizeN, InterYSizeN, CBP::AltRowMajorRX> : public Uninstantiable {
    /*
     * Visual and hardware pixel flow/movement example for 4x4
     *
     * Visual             Hardware
     * |  0  1  2  3 |    |  3  2  1  0 |
     * |  4  5  6  7 | -> |  4  5  6  7 |
     * |  8  9 10 11 |    | 11 10  9  8 |
     * | 12 13 14 15 |    | 12 13 14 15 |
     *
     * Hardware pixel flow/movement example for 4x4 (pixel and memory address dump)
     *
     * | (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address |
     * | (3,0) (2,0) (1,0) (0,0) |   |  3  2  1  0 |
     * | (0,1) (1,1) (2,1) (3,1) |   |  4  5  6  7 |
     * | (3,2) (2,2) (1,2) (0,2) |   | 11 10  9  8 |
     * | (0,3) (1,3) (2,3) (3,3) |   | 12 13 14 15 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    { return (y & 1) ? (x + y * XSizeN) : ( (XSizeN - 1 - x) + y * XSizeN ); }
};


template <CBP::SUInt XSizeN, CBP::SUInt YSizeN, CBP::SUInt BlockXSizeN, CBP::SUInt BlockYSizeN, CBP::SUInt InterYSizeN>
struct ColorBufferLayoutPolicy<XSizeN, YSizeN, BlockXSizeN, BlockYSizeN, InterYSizeN, CBP::AltRowMajorRY> : public Uninstantiable {
    /*
     * Visual and hardware pixel flow/movement example for 4x4
     *
     * Visual             Hardware
     * |  0  1  2  3 |    | 15 14 13 12 |
     * |  4  5  6  7 | -> |  8  9 10 11 |
     * |  8  9 10 11 |    |  7  6  5  4 |
     * | 12 13 14 15 |    |  0  1  2  3 |
     *
     * Hardware pixel flow/movement example for 4x4 (pixel and memory address dump)
     *
     * | (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address |
     * | (0,3) (1,3) (2,3) (3,3) |   | 12 13 14 15 |
     * | (3,2) (2,2) (1,2) (0,2) |   | 11 10  9  8 |
     * | (0,1) (1,1) (2,1) (3,1) |   |  4  5  6  7 |
     * | (3,0) (2,0) (1,0) (0,0) |   |  3  2  1  0 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    { return (y & 1) ? ( x + (YSizeN - 1 - y) * XSizeN ) : ( (XSizeN - 1 - x) + (YSizeN - 1 - y) * XSizeN ); }
};


template <CBP::SUInt XSizeN, CBP::SUInt YSizeN, CBP::SUInt BlockXSizeN, CBP::SUInt BlockYSizeN, CBP::SUInt InterYSizeN>
struct ColorBufferLayoutPolicy<XSizeN, YSizeN, BlockXSizeN, BlockYSizeN, InterYSizeN, CBP::AltRowMajorRXY> : public Uninstantiable {
    /*
     * Visual and hardware pixel flow/movement example for 4x4
     *
     * Visual             Hardware
     * |  0  1  2  3 |    | 12 13 14 15 |
     * |  4  5  6  7 | -> | 11 10  9  8 |
     * |  8  9 10 11 |    |  4  5  6  7 |
     * | 12 13 14 15 |    |  3  2  1  0 |
     *
     * Hardware pixel flow/movement example for 4x4 (pixel and memory address dump)
     *
     * | (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address |
     * | (3,3) (2,3) (1,3) (0,3) |   | 15 14 13 12 |
     * | (0,2) (1,2) (2,2) (3,2) |   |  8  9 10 11 |
     * | (3,1) (2,1) (1,1) (0,1) |   |  7  6  5  4 |
     * | (0,0) (1,0) (2,0) (3,0) |   |  0  1  2  3 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    { return (y & 1) ? ( (XSizeN - 1 - x) + (YSizeN - 1 - y) * XSizeN ) : ( x + (YSizeN - 1 - y) * XSizeN ); }
};


////////////////////////////////////////////////////////////////////////////////////////////////////


template <CBP::SUInt XSizeN, CBP::SUInt YSizeN, CBP::SUInt BlockXSizeN, CBP::SUInt BlockYSizeN, CBP::SUInt InterYSizeN>
struct ColorBufferLayoutPolicy<XSizeN, YSizeN, BlockXSizeN, BlockYSizeN, InterYSizeN, CBP::AltColMajor> : public Uninstantiable {
    /*
     * Visual and hardware pixel flow/movement example for 4x4
     *
     * Visual             Hardware
     * |  0  1  2  3 |    |  0  7  8 15 |
     * |  4  5  6  7 | -> |  1  6  9 14 |
     * |  8  9 10 11 |    |  2  5 10 13 |
     * | 12 13 14 15 |    |  3  4 11 12 |
     *
     * Hardware pixel flow/movement example for 4x4 (pixel and memory address dump)
     *
     * | (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address |
     * | (0,0) (0,1) (0,2) (0,3) |   |  0  4  8 12 |
     * | (1,3) (1,2) (1,1) (1,0) |   | 13  9  5  1 |
     * | (2,0) (2,1) (2,2) (2,3) |   |  2  6 10 14 |
     * | (3,3) (3,2) (3,1) (3,0) |   | 15 11  7  3 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    { return (x & 1) ? ( (YSizeN - 1 - y) + x * YSizeN ) : (y + x * YSizeN); }
};


template <CBP::SUInt XSizeN, CBP::SUInt YSizeN, CBP::SUInt BlockXSizeN, CBP::SUInt BlockYSizeN, CBP::SUInt InterYSizeN>
struct ColorBufferLayoutPolicy<XSizeN, YSizeN, BlockXSizeN, BlockYSizeN, InterYSizeN, CBP::AltColMajorRX> : public Uninstantiable {
    /*
     * Visual and hardware pixel flow/movement example for 4x4
     *
     * Visual             Hardware
     * |  0  1  2  3 |    | 15  8  7  0 |
     * |  4  5  6  7 | -> | 14  9  6  1 |
     * |  8  9 10 11 |    | 13 10  5  2 |
     * | 12 13 14 15 |    | 12 11  4  3 |
     *
     * Hardware pixel flow/movement example for 4x4 (pixel and memory address dump)
     *
     * | (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address |
     * | (3,0) (3,1) (3,2) (3,3) |   |  3  7 11 15 |
     * | (2,3) (2,2) (2,1) (2,0) |   | 14 10  6  2 |
     * | (1,0) (1,1) (1,2) (1,3) |   |  1  5  9 13 |
     * | (0,3) (0,2) (0,1) (0,0) |   | 12  8  4  0 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    {
        x = XSizeN - 1 - x;

        return (x & 1) ? ( (YSizeN - 1 - y) + x * YSizeN ) : (y + x * YSizeN);
    }
};


template <CBP::SUInt XSizeN, CBP::SUInt YSizeN, CBP::SUInt BlockXSizeN, CBP::SUInt BlockYSizeN, CBP::SUInt InterYSizeN>
struct ColorBufferLayoutPolicy<XSizeN, YSizeN, BlockXSizeN, BlockYSizeN, InterYSizeN, CBP::AltColMajorRY> : public Uninstantiable {
    /*
     * Visual and hardware pixel flow/movement example for 4x4
     *
     * Visual             Hardware
     * |  0  1  2  3 |    |  3  4 11 12 |
     * |  4  5  6  7 | -> |  2  5 10 13 |
     * |  8  9 10 11 |    |  1  6  9 14 |
     * | 12 13 14 15 |    |  0  7  8 15 |
     *
     * Hardware pixel flow/movement example for 4x4 (pixel and memory address dump)
     *
     * | (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address |
     * | (0,3) (0,2) (0,1) (0,0) |   | 12  8  4  0 |
     * | (1,0) (1,1) (1,2) (1,3) |   |  1  5  9 13 |
     * | (2,3) (2,2) (2,1) (2,0) |   | 14 10  6  2 |
     * | (3,0) (3,1) (3,2) (3,3) |   |  3  7 11 15 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    {
        y = YSizeN - 1 - y;

        return (x & 1) ? ( (YSizeN - 1 - y) + x * YSizeN ) : (y + x * YSizeN);
    }
};


template <CBP::SUInt XSizeN, CBP::SUInt YSizeN, CBP::SUInt BlockXSizeN, CBP::SUInt BlockYSizeN, CBP::SUInt InterYSizeN>
struct ColorBufferLayoutPolicy<XSizeN, YSizeN, BlockXSizeN, BlockYSizeN, InterYSizeN, CBP::AltColMajorRXY> : public Uninstantiable {
    /*
     * Visual and hardware pixel flow/movement example for 4x4
     *
     * Visual             Hardware
     * |  0  1  2  3 |    | 12 11  4  3 |
     * |  4  5  6  7 | -> | 13 10  5  2 |
     * |  8  9 10 11 |    | 14  9  6  1 |
     * | 12 13 14 15 |    | 15  8  7  0 |
     *
     * Hardware pixel flow/movement example for 4x4 (pixel and memory address dump)
     *
     * | (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address |
     * | (3,3) (3,2) (3,1) (3,0) |   | 15 11  7  3 |
     * | (2,0) (2,1) (2,2) (2,3) |   |  2  6 10 14 |
     * | (1,3) (1,2) (1,1) (1,0) |   | 13  9  5  1 |
     * | (0,0) (0,1) (0,2) (0,3) |   |  0  4  8 12 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    {
        x = XSizeN - 1 - x;
        y = YSizeN - 1 - y;

        return (x & 1) ? ( (YSizeN - 1 - y) + x * YSizeN ) : (y + x * YSizeN);
    }
};


} // namespace eCxx


#endif
