/*
 * 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_BLOCK_ROW_MAJOR_H
#define ECXX_CTL_GFX_COLOR_BUFFER_LAYOUT_POLICY_BLOCK_ROW_MAJOR_H


namespace eCxx {


//
// Color buffer layout policy constants - block grouped
//
// NOTE : Please see the end of this file for some more detailed explanation.
//
namespace CBP {

    struct BlockRowMajorPixelRowMajor;
    struct BlockRowMajorPixelAltRowMajor;

    struct BlockAltRowMajorPixelRowMajor;
    struct BlockAltRowMajorPixelAltRowMajor;

    struct BlockAltRowMajorAltRXYPixelRowMajor;
    struct BlockAltRowMajorAltRXYPixelAltRowMajor;

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

    struct BlockRowMajorPixelColMajor;
    struct BlockRowMajorPixelAltColMajor;

    struct BlockAltRowMajorPixelColMajor;
    struct BlockAltRowMajorPixelAltColMajor;

    struct BlockAltRowMajorAltRXYPixelColMajor;
    struct BlockAltRowMajorAltRXYPixelAltColMajor;

} // namespace CBP


//
// Implementation of color buffer layout policy structures - block grouped
//
// NOTE : 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::BlockRowMajorPixelRowMajor> : public Uninstantiable {
    static constexpr CBP::DUInt BlockXCountN = XSizeN / BlockXSizeN;
    static constexpr CBP::DUInt BlockYCountN = YSizeN / BlockYSizeN;
    /*
     * Visual and hardware pixel flow/movement example for 8x4 with block size 4x2 (memory address - grouped)
     *
     * Visual                           Hardware
     * |  0  1  2  3    4  5  6  7 |    |  0  1  2  3    8  9 10 11 |
     * |  8  9 10 11   12 13 14 15 |    |  4  5  6  7   12 13 14 15 |
     * |                           | -> |                           |
     * | 16 17 18 19   20 21 22 23 |    | 16 17 18 19   24 25 26 27 |
     * | 24 25 26 27   28 29 30 31 |    | 20 21 22 23   28 29 30 31 |
     *
     * Hardware pixel flow/movement example for 8x4 with block size 4x2 (pixel and memory address dump)
     *
     * | (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address             |
     * | (0,0) (1,0) (2,0) (3,0) (0,1) (1,1) (2,1) (3,1) |   |  0  1  2  3  8  9 10 11 |
     * | (4,0) (5,0) (6,0) (7,0) (4,1) (5,1) (6,1) (7,1) |   |  4  5  6  7 12 13 14 15 |
     * | (0,2) (1,2) (2,2) (3,2) (0,3) (1,3) (2,3) (3,3) |   | 16 17 18 19 24 25 26 27 |
     * | (4,2) (5,2) (6,2) (7,2) (4,3) (5,3) (6,3) (7,3) |   | 20 21 22 23 28 29 30 31 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    {
        const CBP::DUInt bx = x / BlockXSizeN;
        const CBP::DUInt by = y / BlockYSizeN;

        const CBP::DUInt bm = (bx + by * BlockXCountN) * BlockXSizeN * BlockYSizeN;

        const CBP::DUInt px = x % BlockXSizeN;
        const CBP::DUInt py = y % BlockYSizeN;

        const CBP::DUInt pm = py * BlockXSizeN + px;

#if 0
        printf("V.XY(%d, %d) [%2d] -> B.XY(%d, %d) [%d] : P.XY(%d, %d) -> bm=%2d pm=%2d [%2d]\n",
            (int)  x, (int)  y, (int)  x +  y * XSizeN,
            (int) bx, (int) by, (int) bx + by * BlockXCountN,
            (int) px, (int) py,
            (int) bm, (int) pm, (int) bm + pm
          );
#endif

        return bm + pm;
    }
};


template <CBP::SUInt XSizeN, CBP::SUInt YSizeN, CBP::SUInt BlockXSizeN, CBP::SUInt BlockYSizeN, CBP::SUInt InterYSizeN>
struct ColorBufferLayoutPolicy<XSizeN, YSizeN, BlockXSizeN, BlockYSizeN, InterYSizeN, CBP::BlockRowMajorPixelAltRowMajor> : public Uninstantiable {
    static constexpr CBP::DUInt BlockXCountN = XSizeN / BlockXSizeN;
    static constexpr CBP::DUInt BlockYCountN = YSizeN / BlockYSizeN;
    /*
     * Visual and hardware pixel flow/movement example for 8x4 with block size 4x2 (memory address - grouped)
     *
     * Visual                           Hardware
     * |  0  1  2  3    4  5  6  7 |    |  0  1  2  3    8  9 10 11 |
     * |  8  9 10 11   12 13 14 15 |    |  7  6  5  4   15 14 13 12 |
     * |                           | -> |                           |
     * | 16 17 18 19   20 21 22 23 |    | 16 17 18 19   24 25 26 27 |
     * | 24 25 26 27   28 29 30 31 |    | 23 22 21 20   31 30 29 28 |
     *
     * Hardware pixel flow/movement example for 8x4 with block size 4x2 (pixel and memory address dump)
     *
     * | (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address             |
     * | (0,0) (1,0) (2,0) (3,0) (3,1) (2,1) (1,1) (0,1) |   |  0  1  2  3 11 10  9  8 |
     * | (4,0) (5,0) (6,0) (7,0) (7,1) (6,1) (5,1) (4,1) |   |  4  5  6  7 15 14 13 12 |
     * | (0,2) (1,2) (2,2) (3,2) (3,3) (2,3) (1,3) (0,3) |   | 16 17 18 19 27 26 25 24 |
     * | (4,2) (5,2) (6,2) (7,2) (7,3) (6,3) (5,3) (4,3) |   | 20 21 22 23 31 30 29 28 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    {
        const CBP::DUInt bx = x / BlockXSizeN;
        const CBP::DUInt by = y / BlockYSizeN;

        const CBP::DUInt bm = (bx + by * BlockXCountN) * BlockXSizeN * BlockYSizeN;

        const CBP::DUInt px = x % BlockXSizeN;
        const CBP::DUInt py = y % BlockYSizeN;

        const CBP::DUInt pm = ( py & 1 )
                            ? ( py * BlockXSizeN + (BlockXSizeN - 1 - px) )
                            : ( py * BlockXSizeN +                    px  );

        return bm + pm;
    }
};


template <CBP::SUInt XSizeN, CBP::SUInt YSizeN, CBP::SUInt BlockXSizeN, CBP::SUInt BlockYSizeN, CBP::SUInt InterYSizeN>
struct ColorBufferLayoutPolicy<XSizeN, YSizeN, BlockXSizeN, BlockYSizeN, InterYSizeN, CBP::BlockAltRowMajorPixelRowMajor> : public Uninstantiable {
    static constexpr CBP::DUInt BlockXCountN = XSizeN / BlockXSizeN;
    static constexpr CBP::DUInt BlockYCountN = YSizeN / BlockYSizeN;
    /*
     * Visual and hardware pixel flow/movement example for 8x4 with block size 4x2 (memory address - grouped)
     *
     * Visual                           Hardware
     * |  0  1  2  3    4  5  6  7 |    |  0  1  2  3    8  9 10 11 |
     * |  8  9 10 11   12 13 14 15 |    |  4  5  6  7   12 13 14 15 |
     * |                           | -> |                           |
     * | 16 17 18 19   20 21 22 23 |    | 24 25 26 27   16 17 18 19 |
     * | 24 25 26 27   28 29 30 31 |    | 28 29 30 31   20 21 22 23 |
     *
     * Hardware pixel flow/movement example for 8x4 with block size 4x2 (pixel and memory address dump)
     *
     * | (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address             |
     * | (0,0) (1,0) (2,0) (3,0) (0,1) (1,1) (2,1) (3,1) |   |  0  1  2  3  8  9 10 11 |
     * | (4,0) (5,0) (6,0) (7,0) (4,1) (5,1) (6,1) (7,1) |   |  4  5  6  7 12 13 14 15 |
     * | (4,2) (5,2) (6,2) (7,2) (4,3) (5,3) (6,3) (7,3) |   | 20 21 22 23 28 29 30 31 |
     * | (0,2) (1,2) (2,2) (3,2) (0,3) (1,3) (2,3) (3,3) |   | 16 17 18 19 24 25 26 27 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    {
        const CBP::DUInt bx = x / BlockXSizeN;
        const CBP::DUInt by = y / BlockYSizeN;

        const CBP::DUInt bm = ( by & 1 )
                            ? ( ( (BlockXCountN - 1 - bx) + by * BlockXCountN ) * BlockXSizeN * BlockYSizeN )
                            : ( (                     bx  + by * BlockXCountN ) * BlockXSizeN * BlockYSizeN );

        const CBP::DUInt px = x % BlockXSizeN;
        const CBP::DUInt py = y % BlockYSizeN;

        const CBP::DUInt pm = py * BlockXSizeN + px;

        return bm + pm;
    }
};


template <CBP::SUInt XSizeN, CBP::SUInt YSizeN, CBP::SUInt BlockXSizeN, CBP::SUInt BlockYSizeN, CBP::SUInt InterYSizeN>
struct ColorBufferLayoutPolicy<XSizeN, YSizeN, BlockXSizeN, BlockYSizeN, InterYSizeN, CBP::BlockAltRowMajorPixelAltRowMajor> : public Uninstantiable {
    static constexpr CBP::DUInt BlockXCountN = XSizeN / BlockXSizeN;
    static constexpr CBP::DUInt BlockYCountN = YSizeN / BlockYSizeN;
    /*
     * Visual and hardware pixel flow/movement example for 8x4 with block size 4x2 (memory address - grouped)
     *
     * Visual                           Hardware
     * |  0  1  2  3    4  5  6  7 |    |  0  1  2  3    8  9 10 11 |
     * |  8  9 10 11   12 13 14 15 |    |  7  6  5  4   15 14 13 12 |
     * |                           | -> |                           |
     * | 16 17 18 19   20 21 22 23 |    | 24 25 26 27   16 17 18 19 |
     * | 24 25 26 27   28 29 30 31 |    | 31 30 29 28   23 22 21 20 |
     *
     * Hardware pixel flow/movement example for 8x4 with block size 4x2 (pixel and memory address dump)
     *
     * | (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address             |
     * | (0,0) (1,0) (2,0) (3,0) (3,1) (2,1) (1,1) (0,1) |   |  0  1  2  3 11 10  9  8 |
     * | (4,0) (5,0) (6,0) (7,0) (7,1) (6,1) (5,1) (4,1) |   |  4  5  6  7 15 14 13 12 |
     * | (4,2) (5,2) (6,2) (7,2) (7,3) (6,3) (5,3) (4,3) |   | 20 21 22 23 31 30 29 28 |
     * | (0,2) (1,2) (2,2) (3,2) (3,3) (2,3) (1,3) (0,3) |   | 16 17 18 19 27 26 25 24 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    {
        const CBP::DUInt bx = x / BlockXSizeN;
        const CBP::DUInt by = y / BlockYSizeN;

        const CBP::DUInt bm = ( by & 1 )
                            ? ( ( (BlockXCountN - 1 - bx) + by * BlockXCountN ) * BlockXSizeN * BlockYSizeN )
                            : ( (                     bx  + by * BlockXCountN ) * BlockXSizeN * BlockYSizeN );

        const CBP::DUInt px = x % BlockXSizeN;
        const CBP::DUInt py = y % BlockYSizeN;

        const CBP::DUInt pm = ( py & 1 )
                            ? ( py * BlockXSizeN + (BlockXSizeN - 1 - px) )
                            : ( py * BlockXSizeN +                    px  );

        return bm + pm;
    }
};


template <CBP::SUInt XSizeN, CBP::SUInt YSizeN, CBP::SUInt BlockXSizeN, CBP::SUInt BlockYSizeN, CBP::SUInt InterYSizeN>
struct ColorBufferLayoutPolicy<XSizeN, YSizeN, BlockXSizeN, BlockYSizeN, InterYSizeN, CBP::BlockAltRowMajorAltRXYPixelRowMajor> : public Uninstantiable {
    static constexpr CBP::DUInt BlockXCountN = XSizeN / BlockXSizeN;
    static constexpr CBP::DUInt BlockYCountN = YSizeN / BlockYSizeN;
    /*
     * Visual and hardware pixel flow/movement example for 8x4 with block size 4x2 (memory address - grouped)
     *
     * Visual                           Hardware
     * |  0  1  2  3    4  5  6  7 |    |  0  1  2  3    8  9 10 11 |
     * |  8  9 10 11   12 13 14 15 |    |  4  5  6  7   12 13 14 15 |
     * |                           | -> |                           |
     * | 16 17 18 19   20 21 22 23 |    | 31 30 29 28   23 22 21 20 |
     * | 24 25 26 27   28 29 30 31 |    | 27 26 25 24   19 18 17 16 |
     *
     * Hardware pixel flow/movement example for 8x4 with block size 4x2 (pixel and memory address dump)
     *
     * | (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address             |
     * | (0,0) (1,0) (2,0) (3,0) (0,1) (1,1) (2,1) (3,1) |   |  0  1  2  3  8  9 10 11 |
     * | (4,0) (5,0) (6,0) (7,0) (4,1) (5,1) (6,1) (7,1) |   |  4  5  6  7 12 13 14 15 |
     * | (7,3) (6,3) (5,3) (4,3) (7,2) (6,2) (5,2) (4,2) |   | 31 30 29 28 23 22 21 20 |
     * | (3,3) (2,3) (1,3) (0,3) (3,2) (2,2) (1,2) (0,2) |   | 27 26 25 24 19 18 17 16 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    {
        const CBP::DUInt bx = x / BlockXSizeN;
        const CBP::DUInt by = y / BlockYSizeN;

        const CBP::DUInt bm = ( by & 1 )
                            ? ( ( (BlockXCountN - 1 - bx) + by * BlockXCountN ) * BlockXSizeN * BlockYSizeN )
                            : ( (                     bx  + by * BlockXCountN ) * BlockXSizeN * BlockYSizeN );

        const CBP::DUInt px = ( by & 1 )
                            ? ( BlockXSizeN - 1 - ( x % BlockXSizeN ) )
                            : (                   ( x % BlockXSizeN ) );

        const CBP::DUInt py = ( by & 1 )
                            ? ( BlockYSizeN - 1 - ( y % BlockYSizeN ) )
                            : (                   ( y % BlockYSizeN ) );

        const CBP::DUInt pm = py * BlockXSizeN + px;

        return bm + pm;
    }
};


template <CBP::SUInt XSizeN, CBP::SUInt YSizeN, CBP::SUInt BlockXSizeN, CBP::SUInt BlockYSizeN, CBP::SUInt InterYSizeN>
struct ColorBufferLayoutPolicy<XSizeN, YSizeN, BlockXSizeN, BlockYSizeN, InterYSizeN, CBP::BlockAltRowMajorAltRXYPixelAltRowMajor> : public Uninstantiable {
    static constexpr CBP::DUInt BlockXCountN = XSizeN / BlockXSizeN;
    static constexpr CBP::DUInt BlockYCountN = YSizeN / BlockYSizeN;
    /*
     * Visual and hardware pixel flow/movement example for 8x4 with block size 4x2 (memory address - grouped)
     *
     * Visual                           Hardware
     * |  0  1  2  3    4  5  6  7 |    |  0  1  2  3    8  9 10 11 |
     * |  8  9 10 11   12 13 14 15 |    |  7  6  5  4   15 14 13 12 |
     * |                           | -> |                           |
     * | 16 17 18 19   20 21 22 23 |    | 28 29 30 31   20 21 22 23 |
     * | 24 25 26 27   28 29 30 31 |    | 27 26 25 24   19 18 17 16 |
     *
     * Hardware pixel flow/movement example for 8x4 with block size 4x2 (pixel and memory address dump)
     *
     * | (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address             |
     * | (0,0) (1,0) (2,0) (3,0) (3,1) (2,1) (1,1) (0,1) |   |  0  1  2  3 11 10  9  8 |
     * | (4,0) (5,0) (6,0) (7,0) (7,1) (6,1) (5,1) (4,1) |   |  4  5  6  7 15 14 13 12 |
     * | (7,3) (6,3) (5,3) (4,3) (4,2) (5,2) (6,2) (7,2) |   | 31 30 29 28 20 21 22 23 |
     * | (3,3) (2,3) (1,3) (0,3) (0,2) (1,2) (2,2) (3,2) |   | 27 26 25 24 16 17 18 19 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    {
        const CBP::DUInt bx = x / BlockXSizeN;
        const CBP::DUInt by = y / BlockYSizeN;

        const CBP::DUInt bm = ( by & 1 )
                            ? ( ( (BlockXCountN - 1 - bx) + by * BlockXCountN ) * BlockXSizeN * BlockYSizeN )
                            : ( (                     bx  + by * BlockXCountN ) * BlockXSizeN * BlockYSizeN );

        const CBP::DUInt px = ( by & 1 )
                            ? ( BlockXSizeN - 1 - ( x % BlockXSizeN ) )
                            : (                   ( x % BlockXSizeN ) );

        const CBP::DUInt py = ( by & 1 )
                            ? ( BlockYSizeN - 1 - ( y % BlockYSizeN ) )
                            : (                   ( y % BlockYSizeN ) );

        const CBP::DUInt pm = ( py & 1 )
                            ? ( py * BlockXSizeN + (BlockXSizeN - 1 - px) )
                            : ( py * BlockXSizeN +                    px  );

        return bm + pm;
    }
};


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


template <CBP::SUInt XSizeN, CBP::SUInt YSizeN, CBP::SUInt BlockXSizeN, CBP::SUInt BlockYSizeN, CBP::SUInt InterYSizeN>
struct ColorBufferLayoutPolicy<XSizeN, YSizeN, BlockXSizeN, BlockYSizeN, InterYSizeN, CBP::BlockRowMajorPixelColMajor> : public Uninstantiable {
    static constexpr CBP::DUInt BlockXCountN = XSizeN / BlockXSizeN;
    static constexpr CBP::DUInt BlockYCountN = YSizeN / BlockYSizeN;
    /*
     * Visual and hardware pixel flow/movement example for 8x4 with block size 4x2 (memory address - grouped)
     *
     * Visual                           Hardware
     * |  0  1  2  3    4  5  6  7 |    |  0  2  4  6    8 10 12 14 |
     * |  8  9 10 11   12 13 14 15 |    |  1  3  5  7    9 11 13 15 |
     * |                           | -> |                           |
     * | 16 17 18 19   20 21 22 23 |    | 16 18 20 22   24 26 28 30 |
     * | 24 25 26 27   28 29 30 31 |    | 17 19 21 23   25 27 29 31 |
     *
     * Hardware pixel flow/movement example for 8x4 with block size 4x2 (pixel and memory address dump)
     *
     * | (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address             |
     * | (0,0) (0,1) (1,0) (1,1) (2,0) (2,1) (3,0) (3,1) |   |  0  8  1  9  2 10  3 11 |
     * | (4,0) (4,1) (5,0) (5,1) (6,0) (6,1) (7,0) (7,1) |   |  4 12  5 13  6 14  7 15 |
     * | (0,2) (0,3) (1,2) (1,3) (2,2) (2,3) (3,2) (3,3) |   | 16 24 17 25 18 26 19 27 |
     * | (4,2) (4,3) (5,2) (5,3) (6,2) (6,3) (7,2) (7,3) |   | 20 28 21 29 22 30 23 31 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    {
        const CBP::DUInt bx = x / BlockXSizeN;
        const CBP::DUInt by = y / BlockYSizeN;

        const CBP::DUInt bm = (bx + by * BlockXCountN) * BlockXSizeN * BlockYSizeN;

        const CBP::DUInt px = x % BlockXSizeN;
        const CBP::DUInt py = y % BlockYSizeN;

        const CBP::DUInt pm = px * BlockYSizeN + py;

        return bm + pm;
    }
};


template <CBP::SUInt XSizeN, CBP::SUInt YSizeN, CBP::SUInt BlockXSizeN, CBP::SUInt BlockYSizeN, CBP::SUInt InterYSizeN>
struct ColorBufferLayoutPolicy<XSizeN, YSizeN, BlockXSizeN, BlockYSizeN, InterYSizeN, CBP::BlockRowMajorPixelAltColMajor> : public Uninstantiable {
    static constexpr CBP::DUInt BlockXCountN = XSizeN / BlockXSizeN;
    static constexpr CBP::DUInt BlockYCountN = YSizeN / BlockYSizeN;
    /*
     * Visual and hardware pixel flow/movement example for 8x4 with block size 4x2 (memory address - grouped)
     *
     * Visual                           Hardware
     * |  0  1  2  3    4  5  6  7 |    |  0  3  4  7    8 11 12 15 |
     * |  8  9 10 11   12 13 14 15 |    |  1  2  5  6    9 10 13 14 |
     * |                           | -> |                           |
     * | 16 17 18 19   20 21 22 23 |    | 16 19 20 23   24 27 28 31 |
     * | 24 25 26 27   28 29 30 31 |    | 17 18 21 22   25 26 29 30 |
     *
     * Hardware pixel flow/movement example for 8x4 with block size 4x2 (pixel and memory address dump)
     *
     * | (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address             |
     * | (0,0) (0,1) (1,1) (1,0) (2,0) (2,1) (3,1) (3,0) |   |  0  8  9  1  2 10 11  3 |
     * | (4,0) (4,1) (5,1) (5,0) (6,0) (6,1) (7,1) (7,0) |   |  4 12 13  5  6 14 15  7 |
     * | (0,2) (0,3) (1,3) (1,2) (2,2) (2,3) (3,3) (3,2) |   | 16 24 25 17 18 26 27 19 |
     * | (4,2) (4,3) (5,3) (5,2) (6,2) (6,3) (7,3) (7,2) |   | 20 28 29 21 22 30 31 23 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    {
        const CBP::DUInt bx = x / BlockXSizeN;
        const CBP::DUInt by = y / BlockYSizeN;

        const CBP::DUInt bm = (bx + by * BlockXCountN) * BlockXSizeN * BlockYSizeN;

        const CBP::DUInt px = x % BlockXSizeN;
        const CBP::DUInt py = y % BlockYSizeN;

        const CBP::DUInt pm = (px & 1)
                            ? ( px * BlockYSizeN + (BlockYSizeN - 1 - py) )
                            : ( px * BlockYSizeN +                    py  );

        return bm + pm;
    }
};


template <CBP::SUInt XSizeN, CBP::SUInt YSizeN, CBP::SUInt BlockXSizeN, CBP::SUInt BlockYSizeN, CBP::SUInt InterYSizeN>
struct ColorBufferLayoutPolicy<XSizeN, YSizeN, BlockXSizeN, BlockYSizeN, InterYSizeN, CBP::BlockAltRowMajorPixelColMajor> : public Uninstantiable {
    static constexpr CBP::DUInt BlockXCountN = XSizeN / BlockXSizeN;
    static constexpr CBP::DUInt BlockYCountN = YSizeN / BlockYSizeN;
    /*
     * Visual and hardware pixel flow/movement example for 8x4 with block size 4x2 (memory address - grouped)
     *
     * Visual                           Hardware
     * |  0  1  2  3    4  5  6  7 |    |  0  2  4  6    8 10 12 14 |
     * |  8  9 10 11   12 13 14 15 |    |  1  3  5  7    9 11 13 15 |
     * |                           | -> |                           |
     * | 16 17 18 19   20 21 22 23 |    | 24 26 28 30   16 18 20 22 |
     * | 24 25 26 27   28 29 30 31 |    | 25 27 29 31   17 19 21 23 |
     *
     * Hardware pixel flow/movement example for 8x4 with block size 4x2 (pixel and memory address dump)
     *
     * | (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address             |
     * | (0,0) (0,1) (1,0) (1,1) (2,0) (2,1) (3,0) (3,1) |   |  0  8  1  9  2 10  3 11 |
     * | (4,0) (4,1) (5,0) (5,1) (6,0) (6,1) (7,0) (7,1) |   |  4 12  5 13  6 14  7 15 |
     * | (4,2) (4,3) (5,2) (5,3) (6,2) (6,3) (7,2) (7,3) |   | 20 28 21 29 22 30 23 31 |
     * | (0,2) (0,3) (1,2) (1,3) (2,2) (2,3) (3,2) (3,3) |   | 16 24 17 25 18 26 19 27 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    {
        const CBP::DUInt bx = x / BlockXSizeN;
        const CBP::DUInt by = y / BlockYSizeN;

        const CBP::DUInt bm = ( by & 1 )
                            ? ( ( (BlockXCountN - 1 - bx) + by * BlockXCountN ) * BlockXSizeN * BlockYSizeN )
                            : ( (                     bx  + by * BlockXCountN ) * BlockXSizeN * BlockYSizeN );

        const CBP::DUInt px = x % BlockXSizeN;
        const CBP::DUInt py = y % BlockYSizeN;

        const CBP::DUInt pm = px * BlockYSizeN + py;

        return bm + pm;
    }
};


template <CBP::SUInt XSizeN, CBP::SUInt YSizeN, CBP::SUInt BlockXSizeN, CBP::SUInt BlockYSizeN, CBP::SUInt InterYSizeN>
struct ColorBufferLayoutPolicy<XSizeN, YSizeN, BlockXSizeN, BlockYSizeN, InterYSizeN, CBP::BlockAltRowMajorPixelAltColMajor> : public Uninstantiable {
    static constexpr CBP::DUInt BlockXCountN = XSizeN / BlockXSizeN;
    static constexpr CBP::DUInt BlockYCountN = YSizeN / BlockYSizeN;
    /*
     * Visual and hardware pixel flow/movement example for 8x4 with block size 4x2 (memory address - grouped)
     *
     * Visual                           Hardware
     * |  0  1  2  3    4  5  6  7 |    |  0  3  4  7    8 11 12 15 |
     * |  8  9 10 11   12 13 14 15 |    |  1  2  5  6    9 10 13 14 |
     * |                           | -> |                           |
     * | 16 17 18 19   20 21 22 23 |    | 24 27 28 31   16 19 20 23 |
     * | 24 25 26 27   28 29 30 31 |    | 25 26 29 30   17 18 21 22 |
     *
     * Hardware pixel flow/movement example for 8x4 with block size 4x2 (pixel and memory address dump)
     *
     * | (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address             |
     * | (0,0) (0,1) (1,1) (1,0) (2,0) (2,1) (3,1) (3,0) |   |  0  8  9  1  2 10 11  3 |
     * | (4,0) (4,1) (5,1) (5,0) (6,0) (6,1) (7,1) (7,0) |   |  4 12 13  5  6 14 15  7 |
     * | (4,2) (4,3) (5,3) (5,2) (6,2) (6,3) (7,3) (7,2) |   | 20 28 29 21 22 30 31 23 |
     * | (0,2) (0,3) (1,3) (1,2) (2,2) (2,3) (3,3) (3,2) |   | 16 24 25 17 18 26 27 19 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    {
        const CBP::DUInt bx = x / BlockXSizeN;
        const CBP::DUInt by = y / BlockYSizeN;

        const CBP::DUInt bm = ( by & 1 )
                            ? ( ( (BlockXCountN - 1 - bx) + by * BlockXCountN ) * BlockXSizeN * BlockYSizeN )
                            : ( (                     bx  + by * BlockXCountN ) * BlockXSizeN * BlockYSizeN );

        const CBP::DUInt px = x % BlockXSizeN;
        const CBP::DUInt py = y % BlockYSizeN;

        const CBP::DUInt pm = (px & 1)
                            ? ( px * BlockYSizeN + (BlockYSizeN - 1 - py) )
                            : ( px * BlockYSizeN +                    py  );

        return bm + pm;
    }
};


template <CBP::SUInt XSizeN, CBP::SUInt YSizeN, CBP::SUInt BlockXSizeN, CBP::SUInt BlockYSizeN, CBP::SUInt InterYSizeN>
struct ColorBufferLayoutPolicy<XSizeN, YSizeN, BlockXSizeN, BlockYSizeN, InterYSizeN, CBP::BlockAltRowMajorAltRXYPixelColMajor> : public Uninstantiable {
    static constexpr CBP::DUInt BlockXCountN = XSizeN / BlockXSizeN;
    static constexpr CBP::DUInt BlockYCountN = YSizeN / BlockYSizeN;
    /*
     * Visual and hardware pixel flow/movement example for 8x4 with block size 4x2 (memory address - grouped)
     *
     * Visual                           Hardware
     * |  0  1  2  3    4  5  6  7 |    |  0  2  4  6    8 10 12 14 |
     * |  8  9 10 11   12 13 14 15 |    |  1  3  5  7    9 11 13 15 |
     * |                           | -> |                           |
     * | 16 17 18 19   20 21 22 23 |    | 31 29 27 25   23 21 19 17 |
     * | 24 25 26 27   28 29 30 31 |    | 30 28 26 24   22 20 18 16 |
     *
     * Hardware pixel flow/movement example for 8x4 with block size 4x2 (pixel and memory address dump)
     *
     * | (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address             |
     * | (0,0) (0,1) (1,0) (1,1) (2,0) (2,1) (3,0) (3,1) |   |  0  8  1  9  2 10  3 11 |
     * | (4,0) (4,1) (5,0) (5,1) (6,0) (6,1) (7,0) (7,1) |   |  4 12  5 13  6 14  7 15 |
     * | (7,3) (7,2) (6,3) (6,2) (5,3) (5,2) (4,3) (4,2) |   | 31 23 30 22 29 21 28 20 |
     * | (3,3) (3,2) (2,3) (2,2) (1,3) (1,2) (0,3) (0,2) |   | 27 19 26 18 25 17 24 16 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    {
        const CBP::DUInt bx = x / BlockXSizeN;
        const CBP::DUInt by = y / BlockYSizeN;

        const CBP::DUInt bm = ( by & 1 )
                            ? ( ( (BlockXCountN - 1 - bx) + by * BlockXCountN ) * BlockXSizeN * BlockYSizeN )
                            : ( (                     bx  + by * BlockXCountN ) * BlockXSizeN * BlockYSizeN );

        const CBP::DUInt px = ( by & 1 )
                            ? ( BlockXSizeN - 1 - ( x % BlockXSizeN ) )
                            : (                   ( x % BlockXSizeN ) );

        const CBP::DUInt py = ( by & 1 )
                            ? ( BlockYSizeN - 1 - ( y % BlockYSizeN ) )
                            : (                   ( y % BlockYSizeN ) );

        const CBP::DUInt pm = px * BlockYSizeN + py;

        return bm + pm;
    }
};


template <CBP::SUInt XSizeN, CBP::SUInt YSizeN, CBP::SUInt BlockXSizeN, CBP::SUInt BlockYSizeN, CBP::SUInt InterYSizeN>
struct ColorBufferLayoutPolicy<XSizeN, YSizeN, BlockXSizeN, BlockYSizeN, InterYSizeN, CBP::BlockAltRowMajorAltRXYPixelAltColMajor> : public Uninstantiable {
    static constexpr CBP::DUInt BlockXCountN = XSizeN / BlockXSizeN;
    static constexpr CBP::DUInt BlockYCountN = YSizeN / BlockYSizeN;
    /*
     * Visual and hardware pixel flow/movement example for 8x4 with block size 4x2 (memory address - grouped)
     *
     * Visual                           Hardware
     * |  0  1  2  3    4  5  6  7 |    |  0  3  4  7    8 11 12 15 |
     * |  8  9 10 11   12 13 14 15 |    |  1  2  5  6    9 10 13 14 |
     * |                           | -> |                           |
     * | 16 17 18 19   20 21 22 23 |    | 30 29 26 25   22 21 18 17 |
     * | 24 25 26 27   28 29 30 31 |    | 31 28 27 24   23 20 19 16 |
     *
     * Hardware pixel flow/movement example for 8x4 with block size 4x2 (pixel and memory address dump)
     *
     * | (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address             |
     * | (0,0) (0,1) (1,1) (1,0) (2,0) (2,1) (3,1) (3,0) |   |  0  8  9  1  2 10 11  3 |
     * | (4,0) (4,1) (5,1) (5,0) (6,0) (6,1) (7,1) (7,0) |   |  4 12 13  5  6 14 15  7 |
     * | (7,3) (7,2) (6,2) (6,3) (5,3) (5,2) (4,2) (4,3) |   | 31 23 22 30 29 21 20 28 |
     * | (3,3) (3,2) (2,2) (2,3) (1,3) (1,2) (0,2) (0,3) |   | 27 19 18 26 25 17 16 24 |
     */
    static inline CBP::DUInt _(CBP::DUInt x, CBP::DUInt y)
    {
        const CBP::DUInt bx = x / BlockXSizeN;
        const CBP::DUInt by = y / BlockYSizeN;

        const CBP::DUInt bm = ( by & 1 )
                            ? ( ( (BlockXCountN - 1 - bx) + by * BlockXCountN ) * BlockXSizeN * BlockYSizeN )
                            : ( (                     bx  + by * BlockXCountN ) * BlockXSizeN * BlockYSizeN );

        const CBP::DUInt px = ( by & 1 )
                            ? ( BlockXSizeN - 1 - ( x % BlockXSizeN ) )
                            : (                   ( x % BlockXSizeN ) );

        const CBP::DUInt py = ( by & 1 )
                            ? ( BlockYSizeN - 1 - ( y % BlockYSizeN ) )
                            : (                   ( y % BlockYSizeN ) );

        const CBP::DUInt pm = (px & 1)
                            ? ( px * BlockYSizeN + (BlockYSizeN - 1 - py) )
                            : ( px * BlockYSizeN +                    py  );

        return bm + pm;
    }
};


} // namespace eCxx


#endif


/*
 * The examples below are explained using CBP::BlockRowMajorPixelRowMajor convention.
 *
 * ------------------------------------------------------------------------------------------------------
 *
 * Consider a 6x6 display which is composed of 3x3 matrix. It can be ilustrated as:
 *
 *     Visual (Display View)                             |   Block (Hardware View)
 *     Coordinate XY                Memory Flow          |   Coordinate XY              Number
 *                                                       |
 *     0,0 1,0 2,0  3,0, 4,0, 5,0    0  1  2   3  4  5   |   0,0 0,0 0,0  1,0 1,0 1,0   0 0 0  1 1 1
 *     0,1 1,1 2,1  3,1, 4,1, 5,1    6  7  8   9 10 11   |   0,0 0,0 0,0  1,0 1,0 1,0   0 0 0  1 1 1
 *     0,2 1,2 2,2  3,2, 4,2, 5,2   12 13 14  15 16 17   |   0,0 0,0 0,0  1,0 1,0 1,0   0 0 0  1 1 1
 *                                                       |
 *     0,3 1,3 2,3  3,3, 4,3, 5,3   18 19 20  21 22 23   |   0,1 0,1 0,1  1,1 1,1 1,1   2 2 2  3 3 3
 *     0,4 1,4 2,4  3,4, 4,4, 5,4   24 25 26  27 28 29   |   0,1 0,1 0,1  1,1 1,1 1,1   2 2 2  3 3 3
 *     0,5 1,5 2,5  3,5, 4,5, 5,5   30 31 32  33 34 35   |   0,1 0,1 0,1  1,1 1,1 1,1   2 2 2  3 3 3
 *
 * As shown above, the visual pixels are divided into 4 blocks. Each data block will need to be sent
 * in a full group to the hardware. Therefore, the memory layout must be arranged so that the data of
 * the visual pixels is stored with layout: 0 1 2 6 7 8 12 13 14 3 4 5 9 10 11 ...
 *
 * In another way, it can also be ilustrated as:
 *
 *     Visual   -> Hardware
 *      0  1  2 ->  0  1  2
 *      6  7  8 ->  3  4  5
 *     12 13 14 ->  6  7  8
 *
 *      3  4  5 ->  9 10 11
 *      9 10 11 -> 12 13 14
 *     15 16 17 -> 15 16 17
 *
 *     18 19 20 -> 18 19 20
 *     24 25 26 -> 21 22 23
 *     30 31 32 -> 24 25 26
 *
 *     21 22 23 -> 27 28 29
 *     26 28 29 -> 30 31 32
 *     33 34 35 -> 33 34 35
 *
 * Dumping the hardware pixel flow/movement of ColorFX2D<T> with the above configuration will result in:
 *
 *     | (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address       |
 *     | (0,0) (1,0) (2,0) (0,1) (1,1) (2,1) |   |  0  1  2  6  7  8 |
 *     | (0,2) (1,2) (2,2) (3,0) (4,0) (5,0) |   | 12 13 14  3  4  5 |
 *     | (3,1) (4,1) (5,1) (3,2) (4,2) (5,2) |   |  9 10 11 15 16 17 |
 *     | (0,3) (1,3) (2,3) (0,4) (1,4) (2,4) |   | 18 19 20 24 25 26 |
 *     | (0,5) (1,5) (2,5) (3,3) (4,3) (5,3) |   | 30 31 32 21 22 23 |
 *     | (3,4) (4,4) (5,4) (3,5) (4,5) (5,5) |   | 27 28 29 33 34 35 |
 *
 * The dump result does not produce a visually clear representation due to the fact that the block data
 * grouping does not align properly with the 2D matrix.
 *
 * ------------------------------------------------------------------------------------------------------
 *
 * Now consider a 9x6 display which is composed of 3x3 matrix. It can be ilustrated as:
 *
 *     Visual (Display View)
 *     Coordinate XY                             Memory Flow
 *
 *     0,0 1,0 2,0  3,0, 4,0, 5,0  6,0 7,0 8,0    0  1  2   3  4  5   6  7  8
 *     0,1 1,1 2,1  3,1, 4,1, 5,1  6,1 7,1 8,1    9 10 11  12 13 14  15 16 17
 *     0,2 1,2 2,2  3,2, 4,2, 5,2  6,2 7,2 8,2   18 19 20  21 22 23  24 25 26
 *
 *     0,3 1,3 2,3  3,3, 4,3, 5,3  6,3 7,3 8,3   27 28 29  30 31 32  33 34 35
 *     0,4 1,4 2,4  3,4, 4,4, 5,4  6,4 7,4 8,4   36 37 38  39 40 41  42 43 44
 *     0,5 1,5 2,5  3,5, 4,5, 5,5  6,5 7,5 8,5   45 46 47  48 49 50  51 52 53
 *
 * Dumping the hardware pixel flow/movement of ColorFX2D<T> with the above configuration will result in
 * a more visually clear representation:
 *
 *     | (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) (X,Y) |   | Mem.Address                |
 *     | (0,0) (1,0) (2,0) (0,1) (1,1) (2,1) (0,2) (1,2) (2,2) |   |  0  1  2  9 10 11 18 19 20 |
 *     | (3,0) (4,0) (5,0) (3,1) (4,1) (5,1) (3,2) (4,2) (5,2) |   |  3  4  5 12 13 14 21 22 23 |
 *     | (6,0) (7,0) (8,0) (6,1) (7,1) (8,1) (6,2) (7,2) (8,2) |   |  6  7  8 15 16 17 24 25 26 |
 *     | (0,3) (1,3) (2,3) (0,4) (1,4) (2,4) (0,5) (1,5) (2,5) |   | 27 28 29 36 37 38 45 46 47 |
 *     | (3,3) (4,3) (5,3) (3,4) (4,4) (5,4) (3,5) (4,5) (5,5) |   | 30 31 32 39 40 41 48 49 50 |
 *     | (6,3) (7,3) (8,3) (6,4) (7,4) (8,4) (6,5) (7,5) (8,5) |   | 33 34 35 42 43 44 51 52 53 |
 */
