/*
 * 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_STD_H
#define ECXX_CTL_GFX_COLOR_BUFFER_LAYOUT_POLICY_PLAIN_STD_H


namespace eCxx {


//
// Color buffer layout policy constants - plain
//
namespace CBP {

    struct RowMajor;
    struct RowMajorRX;
    struct RowMajorRY;
    struct RowMajorRXY;

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

    struct ColMajor;
    struct ColMajorRX;
    struct ColMajorRY;
    struct ColMajorRXY;

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

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

    using StandardLayout            = RowMajor;
    using HorizontalFlip            = RowMajorRX;
    using VerticalFlip              = RowMajorRY;
    using BothFlip                  = RowMajorRXY;

    using Rotate90CW                = ColMajorRY;
    using Rotate90CWHorizontalFlip  = ColMajor;
    using Rotate90CWVerticalFlip    = ColMajorRXY;
    using Rotate90CWBothFlip        = ColMajorRX;

    using Rotate180CW               = RowMajorRXY;
    using Rotate180CWHorizontalFlip = RowMajorRY;
    using Rotate180CWVerticalFlip   = RowMajorRX;
    using Rotate180CWBothFlip       = RowMajor;

    using Rotate270CW               = ColMajorRX;
    using Rotate270CWHorizontalFlip = ColMajorRXY;
    using Rotate270CWVerticalFlip   = ColMajor;
    using Rotate270CWBothFlip       = ColMajorRY;

} // 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::ColMajor   > : internal::CBEZSwap<XSizeN, YSizeN> {};

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

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

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


//
// Implementation of color buffer layout policy structures - plain
//
// 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::RowMajor> : 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 | -> |  4  5  6  7 |
     * |  8  9 10 11 |    |  8  9 10 11 |
     * | 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 |
     * | (0,0) (1,0) (2,0) (3,0) |   |  0  1  2  3 |
     * | (0,1) (1,1) (2,1) (3,1) |   |  4  5  6  7 |
     * | (0,2) (1,2) (2,2) (3,2) |   |  8  9 10 11 |
     * | (0,3) (1,3) (2,3) (3,3) |   | 12 13 14 15 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    { return 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::RowMajorRX> : 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 | -> |  7  6  5  4 |
     * |  8  9 10 11 |    | 11 10  9  8 |
     * | 12 13 14 15 |    | 15 16 14 12 |
     *
     * 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 |
     * | (3,1) (2,1) (1,1) (0,1) |   |  7  6  5  4 |
     * | (3,2) (2,2) (1,2) (0,2) |   | 11 10  9  8 |
     * | (3,3) (2,3) (1,3) (0,3) |   | 15 14 13 12 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    { return (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::RowMajorRY> : 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 | -> |  8  9 10 11 |
     * |  8  9 10 11 |    |  4  5  6  7 |
     * | 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 |
     * | (0,2) (1,2) (2,2) (3,2) |   |  8  9 10 11 |
     * | (0,1) (1,1) (2,1) (3,1) |   |  4  5  6  7 |
     * | (0,0) (1,0) (2,0) (3,0) |   |  0  1  2  3 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    { return 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::RowMajorRXY> : 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 | -> | 11 10  9  8 |
     * |  8  9 10 11 |    |  7  6  5  4 |
     * | 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 |
     * | (3,2) (2,2) (1,2) (0,2) |   | 11 10  9  8 |
     * | (3,1) (2,1) (1,1) (0,1) |   |  7  6  5  4 |
     * | (3,0) (2,0) (1,0) (0,0) |   |  3  2  1  0 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    { return (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::ColMajor> : public Uninstantiable {
    /*
     * Visual and hardware pixel flow/movement example for 4x4
     *
     * Visual             Hardware
     * |  0  1  2  3 |    |  0  4  8 12 |
     * |  4  5  6  7 | -> |  1  5  9 13 |
     * |  8  9 10 11 |    |  2  6 10 14 |
     * | 12 13 14 15 |    |  3  7 11 15 |
     *
     * 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,0) (1,1) (1,2) (1,3) |   |  1  5  9 13 |
     * | (2,0) (2,1) (2,2) (2,3) |   |  2  6 10 14 |
     * | (3,0) (3,1) (3,2) (3,3) |   |  3  7 11 15 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    { return 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::ColMajorRX> : public Uninstantiable {
    /*
     * Visual and hardware pixel flow/movement example for 4x4
     *
     * Visual             Hardware
     * |  0  1  2  3 |    | 12  8  4  0 |
     * |  4  5  6  7 | -> | 13  9  5  1 |
     * |  8  9 10 11 |    | 14 10  6  2 |
     * | 12 13 14 15 |    | 15 11  7  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,0) (2,1) (2,2) (2,3) |   |  2  6 10 14 |
     * | (1,0) (1,1) (1,2) (1,3) |   |  1  5  9 13 |
     * | (0,0) (0,1) (0,2) (0,3) |   |  0  4  8 12 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    { return y + (XSizeN - 1 - 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::ColMajorRY> : public Uninstantiable {
    /*
     * Visual and hardware pixel flow/movement example for 4x4
     *
     * Visual             Hardware
     * |  0  1  2  3 |    |  3  7 11 15 |
     * |  4  5  6  7 | -> |  2  6 10 14 |
     * |  8  9 10 11 |    |  1  5  9 13 |
     * | 12 13 14 15 |    |  0  4  8 12 |
     *
     * 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,3) (1,2) (1,1) (1,0) |   | 13  9  5  1 |
     * | (2,3) (2,2) (2,1) (2,0) |   | 14 10  6  2 |
     * | (3,3) (3,2) (3,1) (3,0) |   | 15 11  7  3 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    { return (YSizeN - 1 - 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::ColMajorRXY> : public Uninstantiable {
    /*
     * Visual and hardware pixel flow/movement example for 4x4
     *
     * Visual             Hardware
     * |  0  1  2  3 |    | 15 11  7  3 |
     * |  4  5  6  7 | -> | 14 10  6  2 |
     * |  8  9 10 11 |    | 13  9  5  1 |
     * | 12 13 14 15 |    | 12  8  4  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,3) (2,2) (2,1) (2,0) |   | 14 10  6  2 |
     * | (1,3) (1,2) (1,1) (1,0) |   | 13  9  5  1 |
     * | (0,3) (0,2) (0,1) (0,0) |   | 12  8  4  0 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    { return (YSizeN - 1 - y) + (XSizeN - 1 - x) * YSizeN; }
};


} // namespace eCxx


#endif
