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


#include <eCxx/eCxx_ColorSpace.h>

#include "TestUtility.h"


//
// Helper functions
//
template <typename ColorFX1D_T>
static void dumpBufferRaw3(const char* cs, const ColorFX1D_T& colorFX1D)
{
    typename ColorFX1D_T::ConstIterator it = colorFX1D.colorBufferData();

    for(typename ColorFX1D_T::BufferSizeType i = 0; i < ColorFX1D_T::BufferElementCount; ++i) {
        printf( "%s(%03d, %03d, %03d)   ", cs, (int) *(it + 0), (int) *(it + 1), (int) *(it + 2) );
        it += ColorFX1D_T::ColorByteSize;
    }
    printf("\n");
}


template <typename ColorFX1D_T>
static void dumpBufferEnc3(const char* cs, const ColorFX1D_T& colorFX1D)
{
    typename ColorFX1D_T::ConstIterator it = colorFX1D.colorBufferData();

    for(typename ColorFX1D_T::BufferSizeType i = 0; i < ColorFX1D_T::BufferElementCount; ++i) {
        printf( "%s(%03d, %03d, %03d)   ", cs, (int) it->c0, (int) it->c1, (int) it->c2 );
        ++it;
    }
    printf("\n");
}


template <typename ColorFX1D_T>
static void dumpBufferRaw3Sum(const char* cs, const ColorFX1D_T& colorFX1D)
{
    typename ColorFX1D_T::ConstIterator it = colorFX1D.colorBufferData();

    printf("%s\n", cs);
    for(typename ColorFX1D_T::BufferSizeType i = 0; i < ColorFX1D_T::BufferElementCount; ++i) {
        printf( "%02d ", (int) *(it + 0) + *(it + 1) + *(it + 2) );
        it += ColorFX1D_T::ColorByteSize;
    }
    printf("\n");
}


template <typename ColorFX1D_T>
static void dumpBufferEnc3Sum(const char* cs, const ColorFX1D_T& colorFX1D)
{
    typename ColorFX1D_T::ConstIterator it = colorFX1D.colorBufferData();

    printf("%s\n", cs);
    for(typename ColorFX1D_T::BufferSizeType i = 0; i < ColorFX1D_T::BufferElementCount; ++i) {
        printf( "%02d ", (int) it->c0 + it->c1 + it->c2 );
        ++it;
    }
    printf("\n");
}


template <typename ColorFX1D_T>
static void dumpBufferRaw4(const char* cs, const ColorFX1D_T& colorFX1D)
{
    typename ColorFX1D_T::ConstIterator it = colorFX1D.colorBufferData();

    for(typename ColorFX1D_T::BufferSizeType i = 0; i < ColorFX1D_T::BufferElementCount; ++i) {
        printf( "%s(%03d, %03d, %03d, %03d)   ", cs, (int) *(it + 0), (int) *(it + 1), (int) *(it + 2), (int) *(it + 3) );
        it += ColorFX1D_T::ColorByteSize;
    }
    printf("\n");
}


template <typename ColorFX1D_T>
static void dumpBuffer4Enc(const char* cs, const ColorFX1D_T& colorFX1D)
{
    typename ColorFX1D_T::ConstIterator it = colorFX1D.colorBufferData();

    for(typename ColorFX1D_T::BufferSizeType i = 0; i < ColorFX1D_T::BufferElementCount; ++i) {
        printf( "%s(%03d, %03d, %03d, %03d)   ", cs, (int) it->c0, (int) it->c1, (int) it->c2, (int) it->c3 );
        ++it;
    }
    printf("\n");
}


//
// Test application
//
int main()
{
    printf("\n");
    const eCxx::HSVColor hsv0( 30, 128, 200);
    const eCxx::HSVColor hsv1(  0, 200, 200);
    const eCxx::HSVColor hsv2(359, 200, 200);



    eCxx::ColorFX1D<eCxx::RGBColor, 4, eCxx::CBP::RawBuffer> colorFXRGBRawRGB;
    eCxx::ColorFX1D<eCxx::GBRColor, 4, eCxx::CBP::RawBuffer> colorFXRGBRawGBR;
    colorFXRGBRawRGB.set (hsv0           ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawGBR.set (hsv0           ); dumpBufferRaw3("GBR", colorFXRGBRawGBR);
    printf("\n");
    colorFXRGBRawRGB.set (hsv1           ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    printf("\n");
    colorFXRGBRawRGB.lerp(hsv1, hsv2,   0); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.lerp(hsv1, hsv2,  25); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.lerp(hsv1, hsv2,  50); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.lerp(hsv1, hsv2, 100); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    printf("\n");
    printf("Red   = %3d\n", colorFXRGBRawRGB.get(2).r() );
    printf("Green = %3d\n", colorFXRGBRawRGB.get(2).g() );
    printf("Blue  = %3d\n", colorFXRGBRawRGB.get(2).b() );
    printf("\n");
    _DIVIDERLINE_DASHSTR_NL2();



    eCxx::ColorFX1D<eCxx::XRGBColor<eCxx::SK9822XPolicy>, 1                      > colorXRGBEncSK9822;
    eCxx::ColorFX1D<eCxx::XRGBColor<eCxx::SK9822XPolicy>, 1, eCxx::CBP::RawBuffer> colorXRGBRawSK9822;
    colorXRGBEncSK9822.lerp(hsv1, hsv2, 0);                         dumpBuffer4Enc("XRGB<SK9822>", colorXRGBEncSK9822);
    colorXRGBEncSK9822.adjust(127); colorXRGBEncSK9822.adjust(127); dumpBuffer4Enc("XRGB<SK9822>", colorXRGBEncSK9822);
    printf("\n");
    colorXRGBRawSK9822.lerp(hsv1, hsv2, 0);                         dumpBufferRaw4("XRGB<SK9822>", colorXRGBRawSK9822);
    colorXRGBRawSK9822.adjust(127); colorXRGBRawSK9822.adjust(127); dumpBufferRaw4("XRGB<SK9822>", colorXRGBRawSK9822);
    printf("\n");
    eCxx::ColorFX1D<eCxx::XBGRColor<eCxx::SK9822XPolicy>, 2                      > colorXBGREncSK9822;
    eCxx::ColorFX1D<eCxx::XBGRColor<eCxx::SK9822XPolicy>, 2, eCxx::CBP::RawBuffer> colorXBGRRawSK9822;
    colorXBGREncSK9822.lerp(hsv1, hsv2, 0);                         dumpBuffer4Enc("XBGR<SK9822>", colorXBGREncSK9822);
    colorXBGREncSK9822.adjust(127); colorXBGREncSK9822.adjust(127); dumpBuffer4Enc("XBGR<SK9822>", colorXBGREncSK9822);
    printf("\n");
    colorXBGRRawSK9822.lerp(hsv1, hsv2, 0);                         dumpBufferRaw4("XBGR<SK9822>", colorXBGRRawSK9822);
    colorXBGRRawSK9822.adjust(127); colorXBGRRawSK9822.adjust(127); dumpBufferRaw4("XBGR<SK9822>", colorXBGRRawSK9822);
    printf("\n");
    _DIVIDERLINE_DASHSTR_NL2();
    eCxx::ColorFX1D<eCxx::XRGBColor<eCxx::P9813BGRXPolicy>, 1                      > colorXRGBEncP9813;
    eCxx::ColorFX1D<eCxx::XRGBColor<eCxx::P9813BGRXPolicy>, 1, eCxx::CBP::RawBuffer> colorXRGBRawP9813;
    colorXRGBEncP9813.lerp(hsv1, hsv2, 0);                        dumpBuffer4Enc("XRGB<P9813BGR>", colorXRGBEncP9813);
    colorXRGBEncP9813.adjust(127); colorXRGBEncP9813.adjust(127); dumpBuffer4Enc("XRGB<P9813BGR>", colorXRGBEncP9813);
    printf("\n");
    colorXRGBRawP9813.lerp(hsv1, hsv2, 0);                        dumpBufferRaw4("XRGB<P9813BGR>", colorXRGBRawP9813);
    colorXRGBRawP9813.adjust(127); colorXRGBRawP9813.adjust(127); dumpBufferRaw4("XRGB<P9813BGR>", colorXRGBRawP9813);
    printf("\n");
    eCxx::ColorFX1D<eCxx::XBGRColor<eCxx::P9813BGRXPolicy>, 2                      > colorXBGREncP9813;
    eCxx::ColorFX1D<eCxx::XBGRColor<eCxx::P9813BGRXPolicy>, 2, eCxx::CBP::RawBuffer> colorXBGRRawP9813;
    colorXBGREncP9813.lerp(hsv1, hsv2, 0);                        dumpBuffer4Enc("XBGR<P9813BGR>", colorXBGREncP9813);
    colorXBGREncP9813.adjust(127); colorXBGREncP9813.adjust(127); dumpBuffer4Enc("XBGR<P9813BGR>", colorXBGREncP9813);
    printf("\n");
    colorXBGRRawP9813.lerp(hsv1, hsv2, 0);                        dumpBufferRaw4("XBGR<P9813BGR>", colorXBGRRawP9813);
    colorXBGRRawP9813.adjust(127); colorXBGRRawP9813.adjust(127); dumpBufferRaw4("XBGR<P9813BGR>", colorXBGRRawP9813);
    printf("\n");
    _DIVIDERLINE_DASHSTR_NL2();



    eCxx::ColorFX1D<eCxx::RGBColor, 4> colorFXRGB;
    eCxx::ColorFX1D<eCxx::GBRColor, 4> colorFXGBR;
    colorFXRGB.set (hsv0           ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXGBR.set (hsv0           ); dumpBufferEnc3("GBR", colorFXGBR);
    printf("\n");
    colorFXRGB.set (hsv1           ); dumpBufferEnc3("RGB", colorFXRGB);
    printf("\n");
    colorFXRGB.lerp(hsv1, hsv2,   0); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(hsv1, hsv2,  25); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(hsv1, hsv2,  50); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(hsv1, hsv2, 100); dumpBufferEnc3("RGB", colorFXRGB);
    printf("\n");
    printf("Red   = %3d\n", colorFXRGB.get(2).r() );
    printf("Green = %3d\n", colorFXRGB.get(2).g() );
    printf("Blue  = %3d\n", colorFXRGB.get(2).b() );
    printf("\n");
    _DIVIDERLINE_DASHSTR_NL2();



    const eCxx::HSVColor hsvFrom[4] {
      //    H    S    V
        {   0, 200,   0 }, // Red
        { 120, 200,   0 }, // Green
        { 240, 200,   0 }, // Blue
        {   0,   0,   0 }  // White
    };
    const eCxx::HSVColor hsvTo  [4] {
      //    H    S    V
        {   0, 200, 200 }, // Red
        { 120, 200, 200 }, // Green
        { 240, 200, 200 }, // Blue
        {   0,   0, 200 }  // White
    };
    colorFXRGB.lerp<eCxx::HSVColor::V>(hsvFrom, hsvTo,   0); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp<eCxx::HSVColor::V>(hsvFrom, hsvTo,  25); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp<eCxx::HSVColor::V>(hsvFrom, hsvTo,  50); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp<eCxx::HSVColor::V>(hsvFrom, hsvTo, 100); dumpBufferEnc3("RGB", colorFXRGB);
    printf("\n");
    static const eCxx::uint8_t PROGMEM hsvPGMFrom[ (2 + 1 + 1) * 4 ] {
      //  H         S    V
          0,   0, 200,   0, // Red
        120,   0, 200,   0, // Green
        240,   0, 200,   0, // Blue
          0,   0,   0,   0  // White
    };
    static const eCxx::uint8_t PROGMEM hsvPGMTo  [ (2 + 1 + 1) * 4 ] {
      //  H         S    V
          0,   0, 200, 200, // Red
        120,   0, 200, 200, // Green
        240,   0, 200, 200, // Blue
          0,   0,   0, 200  // White
    };
    colorFXRGB.lerp<eCxx::HSVColor::V, eCxx::HSVColor>( eCxx::PGM_PTR(hsvPGMFrom), eCxx::PGM_PTR(hsvPGMTo),   0); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp<eCxx::HSVColor::V, eCxx::HSVColor>( eCxx::PGM_PTR(hsvPGMFrom), eCxx::PGM_PTR(hsvPGMTo),  25); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp<eCxx::HSVColor::V, eCxx::HSVColor>( eCxx::PGM_PTR(hsvPGMFrom), eCxx::PGM_PTR(hsvPGMTo),  50); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp<eCxx::HSVColor::V, eCxx::HSVColor>( eCxx::PGM_PTR(hsvPGMFrom), eCxx::PGM_PTR(hsvPGMTo), 100); dumpBufferEnc3("RGB", colorFXRGB);
    printf("\n");
    _DIVIDERLINE_DASHSTR_NL2();



    const eCxx::RGBColor rgbBlack(0, 0, 0);
    const eCxx::RGBColor rgbMin[4] {
        {   0,   0,   0 },
        {   0,   0,   0 },
        {   0,   0,   0 },
        {   0,   0,   0 }
    };
    const eCxx::RGBColor rgbMax[4] {
        { 255,   0,   0 }, // Red
        {   0, 255,   0 }, // Green
        {   0,   0, 255 }, // Blue
        { 255, 255, 255 }  // White
    };
    static const eCxx::uint8_t PROGMEM rgbPGMMin[3 * 4] {
          0,   0,   0,
          0,   0,   0,
          0,   0,   0,
          0,   0,   0
    };
    static const eCxx::uint8_t PROGMEM rgbPGMMax[3 * 4] {
        255,   0,   0, // Red
          0, 255,   0, // Green
          0,   0, 255, // Blue
        255, 255, 255  // White
    };
    colorFXRGB.lerp(rgbBlack, rgbMax,   0); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbBlack, rgbMax,  25); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbBlack, rgbMax,  50); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbBlack, rgbMax, 100); dumpBufferEnc3("RGB", colorFXRGB);
    printf("\n");
    colorFXRGB.lerp(rgbBlack, eCxx::PGM_PTR(rgbPGMMax),   0); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbBlack, eCxx::PGM_PTR(rgbPGMMax),  25); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbBlack, eCxx::PGM_PTR(rgbPGMMax),  50); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbBlack, eCxx::PGM_PTR(rgbPGMMax), 100); dumpBufferEnc3("RGB", colorFXRGB);
    printf("\n");
    colorFXRGB.lerp(rgbMin, eCxx::PGM_PTR(rgbPGMMax),   0); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbMin, eCxx::PGM_PTR(rgbPGMMax),  25); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbMin, eCxx::PGM_PTR(rgbPGMMax),  50); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbMin, eCxx::PGM_PTR(rgbPGMMax), 100); dumpBufferEnc3("RGB", colorFXRGB);
    printf("\n");
    colorFXRGB.lerp(rgbMax, rgbBlack,   0); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbMax, rgbBlack,  25); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbMax, rgbBlack,  50); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbMax, rgbBlack, 100); dumpBufferEnc3("RGB", colorFXRGB);
    printf("\n");
    colorFXRGB.lerp(eCxx::PGM_PTR(rgbPGMMax), rgbBlack,   0); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(eCxx::PGM_PTR(rgbPGMMax), rgbBlack,  25); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(eCxx::PGM_PTR(rgbPGMMax), rgbBlack,  50); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(eCxx::PGM_PTR(rgbPGMMax), rgbBlack, 100); dumpBufferEnc3("RGB", colorFXRGB);
    printf("\n");
    colorFXRGB.lerp(rgbMax, eCxx::PGM_PTR(rgbPGMMin),   0); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbMax, eCxx::PGM_PTR(rgbPGMMin),  25); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbMax, eCxx::PGM_PTR(rgbPGMMin),  50); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbMax, eCxx::PGM_PTR(rgbPGMMin), 100); dumpBufferEnc3("RGB", colorFXRGB);
    printf("\n");
    _DIVIDERLINE_DASHSTR_NL1();
    _DIVIDERLINE_DASHSTR_NL1();
    _DIVIDERLINE_DASHSTR_NL2();



    colorFXRGBRawRGB.set(rgbMax); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawGBR.set(rgbMax); dumpBufferRaw3("GBR", colorFXRGBRawGBR);
    printf("\n");
    colorFXRGBRawRGB.set<eCxx::RGBColor>( eCxx::PGM_PTR(rgbPGMMax) ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawGBR.set<eCxx::RGBColor>( eCxx::PGM_PTR(rgbPGMMax) ); dumpBufferRaw3("GBR", colorFXRGBRawGBR);
    printf("\n");
                                                                                 dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.set                  ( 0,             *(rgbMax    + 3    ) ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.set<eCxx::RGBColor>( 1, eCxx::PGM_PTR(rgbPGMMax + 3 * 3) ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    printf("\n");
    _DIVIDERLINE_DASHSTR_NL2();



    colorFXRGB.lerp(rgbBlack, rgbMax,   0); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbBlack, rgbMax,  25); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbBlack, rgbMax,  50); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbBlack, rgbMax, 100); dumpBufferEnc3("RGB", colorFXRGB);
    printf("\n");
    colorFXRGB.lerp(rgbBlack, rgbMax,   0); colorFXRGB.cie1931lcc58(); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbBlack, rgbMax,  25); colorFXRGB.cie1931lcc58(); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbBlack, rgbMax,  50); colorFXRGB.cie1931lcc58(); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.lerp(rgbBlack, rgbMax, 100); colorFXRGB.cie1931lcc58(); dumpBufferEnc3("RGB", colorFXRGB);
    printf("\n");
    colorFXRGBRawRGB.lerp(rgbBlack, rgbMax,   0); colorFXRGBRawRGB.cie1931lcc58(); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.lerp(rgbBlack, rgbMax,  25); colorFXRGBRawRGB.cie1931lcc58(); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.lerp(rgbBlack, rgbMax,  50); colorFXRGBRawRGB.cie1931lcc58(); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.lerp(rgbBlack, rgbMax, 100); colorFXRGBRawRGB.cie1931lcc58(); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    printf("\n");

    // Compile test only (to ensure the corresponding function variants are implemented)
    eCxx::ColorFX1D<eCxx::WColor,                         4                      >().cie1931lcc58();
    eCxx::ColorFX1D<eCxx::WColor,                         4, eCxx::CBP::RawBuffer>().cie1931lcc58();
    eCxx::ColorFX1D<eCxx::RGBWColor,                      4                      >().cie1931lcc58();
    eCxx::ColorFX1D<eCxx::RGBWColor,                      4, eCxx::CBP::RawBuffer>().cie1931lcc58();
    eCxx::ColorFX1D<eCxx::WRGBColor,                      4                      >().cie1931lcc58();
    eCxx::ColorFX1D<eCxx::WRGBColor,                      4, eCxx::CBP::RawBuffer>().cie1931lcc58();
    eCxx::ColorFX1D<eCxx::XRGBColor<eCxx::SK9822XPolicy>, 4                      >().cie1931lcc58();
    eCxx::ColorFX1D<eCxx::XRGBColor<eCxx::SK9822XPolicy>, 4, eCxx::CBP::RawBuffer>().cie1931lcc58();

    eCxx::ColorFX1D<eCxx::WColor,                         4                      >().cie1931lut58();
    eCxx::ColorFX1D<eCxx::WColor,                         4, eCxx::CBP::RawBuffer>().cie1931lut58();
    eCxx::ColorFX1D<eCxx::RGBWColor,                      4                      >().cie1931lut58();
    eCxx::ColorFX1D<eCxx::RGBWColor,                      4, eCxx::CBP::RawBuffer>().cie1931lut58();
    eCxx::ColorFX1D<eCxx::WRGBColor,                      4                      >().cie1931lut58();
    eCxx::ColorFX1D<eCxx::WRGBColor,                      4, eCxx::CBP::RawBuffer>().cie1931lut58();
    eCxx::ColorFX1D<eCxx::XRGBColor<eCxx::SK9822XPolicy>, 4                      >().cie1931lut58();
    eCxx::ColorFX1D<eCxx::XRGBColor<eCxx::SK9822XPolicy>, 4, eCxx::CBP::RawBuffer>().cie1931lut58();
    _DIVIDERLINE_DASHSTR_NL1();
    _DIVIDERLINE_DASHSTR_NL1();
    _DIVIDERLINE_DASHSTR_NL2();



    colorFXRGB.lerp (rgbBlack, rgbMax, 100); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.adjust(  -1                ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.adjust(  -2                ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.adjust(   1                ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.adjust(   2                ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.adjust(   2                ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.adjust(-128                ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.adjust(-128                ); dumpBufferEnc3("RGB", colorFXRGB);
    printf("\n");
    colorFXRGBRawRGB.lerp (rgbBlack, rgbMax, 100); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.adjust(  -1                ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.adjust(  -2                ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.adjust(   1                ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.adjust(   2                ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.adjust(   2                ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.adjust(-128                ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.adjust(-128                ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    printf("\n");

    // Compile test only (to ensure the corresponding function variants are implemented)
    eCxx::ColorFX1D<eCxx::HSVColor,                       4                      >().adjust  (-1);
    eCxx::ColorFX1D<eCxx::HSVColor,                       4, eCxx::CBP::RawBuffer>().adjust  (-1);
    eCxx::ColorFX1D<eCxx::HSLColor,                       4                      >().adjust  (-1);
    eCxx::ColorFX1D<eCxx::HSLColor,                       4, eCxx::CBP::RawBuffer>().adjust  (-1);
    eCxx::ColorFX1D<eCxx::KColor,                         4                      >().adjust  (-1);
    eCxx::ColorFX1D<eCxx::KColor,                         4, eCxx::CBP::RawBuffer>().adjust  (-1);
    eCxx::ColorFX1D<eCxx::KColor,                         4                      >().adjust16(-500);
    eCxx::ColorFX1D<eCxx::KColor,                         4, eCxx::CBP::RawBuffer>().adjust16(-500);
    eCxx::ColorFX1D<eCxx::WColor,                         4                      >().adjust  (-1);
    eCxx::ColorFX1D<eCxx::WColor,                         4, eCxx::CBP::RawBuffer>().adjust  (-1);
    eCxx::ColorFX1D<eCxx::RGBWColor,                      4                      >().adjust  (-1);
    eCxx::ColorFX1D<eCxx::RGBWColor,                      4, eCxx::CBP::RawBuffer>().adjust  (-1);
    eCxx::ColorFX1D<eCxx::WRGBColor,                      4                      >().adjust  (-1);
    eCxx::ColorFX1D<eCxx::WRGBColor,                      4, eCxx::CBP::RawBuffer>().adjust  (-1);
    eCxx::ColorFX1D<eCxx::XRGBColor<eCxx::SK9822XPolicy>, 4                      >().adjust  (-1);
    eCxx::ColorFX1D<eCxx::XRGBColor<eCxx::SK9822XPolicy>, 4, eCxx::CBP::RawBuffer>().adjust  (-1);
    eCxx::ColorFX1D<eCxx::HSVColor,                       4                      >().adjust  <eCxx::HSVColor                      ::V>(-1);
    eCxx::ColorFX1D<eCxx::HSVColor,                       4, eCxx::CBP::RawBuffer>().adjust  <eCxx::HSVColor                      ::V>(-1);
    eCxx::ColorFX1D<eCxx::HSLColor,                       4                      >().adjust  <eCxx::HSLColor                      ::L>(-1);
    eCxx::ColorFX1D<eCxx::HSLColor,                       4, eCxx::CBP::RawBuffer>().adjust  <eCxx::HSLColor                      ::L>(-1);
    eCxx::ColorFX1D<eCxx::KColor,                         4                      >().adjust  <eCxx::KColor                        ::K>(-1);
    eCxx::ColorFX1D<eCxx::KColor,                         4, eCxx::CBP::RawBuffer>().adjust  <eCxx::KColor                        ::K>(-1);
    eCxx::ColorFX1D<eCxx::KColor,                         4                      >().adjust16<eCxx::KColor                        ::K>(-500);
    eCxx::ColorFX1D<eCxx::KColor,                         4, eCxx::CBP::RawBuffer>().adjust16<eCxx::KColor                        ::K>(-500);
    eCxx::ColorFX1D<eCxx::WColor,                         4                      >().adjust  <eCxx::WColor                        ::W>(-1);
    eCxx::ColorFX1D<eCxx::WColor,                         4, eCxx::CBP::RawBuffer>().adjust  <eCxx::WColor                        ::W>(-1);
    eCxx::ColorFX1D<eCxx::RGBWColor,                      4                      >().adjust  <eCxx::RGBWColor                     ::G>(-1);
    eCxx::ColorFX1D<eCxx::RGBWColor,                      4, eCxx::CBP::RawBuffer>().adjust  <eCxx::RGBWColor                     ::G>(-1);
    eCxx::ColorFX1D<eCxx::WRGBColor,                      4                      >().adjust  <eCxx::WRGBColor                     ::G>(-1);
    eCxx::ColorFX1D<eCxx::WRGBColor,                      4, eCxx::CBP::RawBuffer>().adjust  <eCxx::WRGBColor                     ::G>(-1);
    eCxx::ColorFX1D<eCxx::XRGBColor<eCxx::SK9822XPolicy>, 4                      >().adjust  <eCxx::XRGBColor<eCxx::SK9822XPolicy>::G>(-1);
    eCxx::ColorFX1D<eCxx::XRGBColor<eCxx::SK9822XPolicy>, 4, eCxx::CBP::RawBuffer>().adjust  <eCxx::XRGBColor<eCxx::SK9822XPolicy>::G>(-1);
    _DIVIDERLINE_DASHSTR_NL2();

    colorFXRGB.lerp (rgbBlack, rgbMax, 100); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.scale(127                  ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.scale( 63                  ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.scale( 63                  ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.scale(255                  ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.scale(255                  ); dumpBufferEnc3("RGB", colorFXRGB);
    printf("\n");
    colorFXRGBRawRGB.lerp (rgbBlack, rgbMax, 100); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.scale(127                  ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.scale( 63                  ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.scale( 63                  ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.scale(255                  ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.scale(255                  ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    printf("\n");

    // Compile test only (to ensure the corresponding function variants are implemented)
    eCxx::ColorFX1D<eCxx::HSVColor,                       4                      >().scale(128);
    eCxx::ColorFX1D<eCxx::HSVColor,                       4, eCxx::CBP::RawBuffer>().scale(128);
    eCxx::ColorFX1D<eCxx::HSLColor,                       4                      >().scale(128);
    eCxx::ColorFX1D<eCxx::HSLColor,                       4, eCxx::CBP::RawBuffer>().scale(128);
    eCxx::ColorFX1D<eCxx::KColor,                         4                      >().scale(128);
    eCxx::ColorFX1D<eCxx::KColor,                         4, eCxx::CBP::RawBuffer>().scale(128);
    eCxx::ColorFX1D<eCxx::WColor,                         4                      >().scale(128);
    eCxx::ColorFX1D<eCxx::WColor,                         4, eCxx::CBP::RawBuffer>().scale(128);
    eCxx::ColorFX1D<eCxx::RGBWColor,                      4                      >().scale(128);
    eCxx::ColorFX1D<eCxx::RGBWColor,                      4, eCxx::CBP::RawBuffer>().scale(128);
    eCxx::ColorFX1D<eCxx::WRGBColor,                      4                      >().scale(128);
    eCxx::ColorFX1D<eCxx::WRGBColor,                      4, eCxx::CBP::RawBuffer>().scale(128);
    eCxx::ColorFX1D<eCxx::XRGBColor<eCxx::SK9822XPolicy>, 4                      >().scale(128);
    eCxx::ColorFX1D<eCxx::XRGBColor<eCxx::SK9822XPolicy>, 4, eCxx::CBP::RawBuffer>().scale(128);
    eCxx::ColorFX1D<eCxx::HSVColor,                       4                      >().scale<eCxx::HSVColor                      ::V>(128);
    eCxx::ColorFX1D<eCxx::HSVColor,                       4, eCxx::CBP::RawBuffer>().scale<eCxx::HSVColor                      ::V>(128);
    eCxx::ColorFX1D<eCxx::HSLColor,                       4                      >().scale<eCxx::HSLColor                      ::L>(128);
    eCxx::ColorFX1D<eCxx::HSLColor,                       4, eCxx::CBP::RawBuffer>().scale<eCxx::HSLColor                      ::L>(128);
    eCxx::ColorFX1D<eCxx::KColor,                         4                      >().scale<eCxx::KColor                        ::K>(128);
    eCxx::ColorFX1D<eCxx::KColor,                         4, eCxx::CBP::RawBuffer>().scale<eCxx::KColor                        ::K>(128);
    eCxx::ColorFX1D<eCxx::WColor,                         4                      >().scale<eCxx::WColor                        ::W>(128);
    eCxx::ColorFX1D<eCxx::WColor,                         4, eCxx::CBP::RawBuffer>().scale<eCxx::WColor                        ::W>(128);
    eCxx::ColorFX1D<eCxx::RGBWColor,                      4                      >().scale<eCxx::RGBWColor                     ::G>(128);
    eCxx::ColorFX1D<eCxx::RGBWColor,                      4, eCxx::CBP::RawBuffer>().scale<eCxx::RGBWColor                     ::G>(128);
    eCxx::ColorFX1D<eCxx::WRGBColor,                      4                      >().scale<eCxx::WRGBColor                     ::G>(128);
    eCxx::ColorFX1D<eCxx::WRGBColor,                      4, eCxx::CBP::RawBuffer>().scale<eCxx::WRGBColor                     ::G>(128);
    eCxx::ColorFX1D<eCxx::XRGBColor<eCxx::SK9822XPolicy>, 4                      >().scale<eCxx::XRGBColor<eCxx::SK9822XPolicy>::G>(128);
    eCxx::ColorFX1D<eCxx::XRGBColor<eCxx::SK9822XPolicy>, 4, eCxx::CBP::RawBuffer>().scale<eCxx::XRGBColor<eCxx::SK9822XPolicy>::G>(128);
    _DIVIDERLINE_DASHSTR_NL2();

    colorFXRGB.lerp       (rgbBlack, rgbMax, 100); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.shiftRight (rgbBlack             ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.shiftRight (rgbBlack             ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.shiftRight (rgbBlack             ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.shiftRight (rgbBlack             ); dumpBufferEnc3("RGB", colorFXRGB);
    printf("\n");
    colorFXRGB.lerp       (rgbBlack, rgbMax, 100); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.shiftLeft  (rgbBlack             ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.shiftLeft  (rgbBlack             ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.shiftLeft  (rgbBlack             ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.shiftLeft  (rgbBlack             ); dumpBufferEnc3("RGB", colorFXRGB);
    printf("\n");
    colorFXRGB.lerp       (rgbBlack, rgbMax, 100); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.rotateRight(                     ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.rotateRight(                     ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.rotateRight(                     ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.rotateRight(                     ); dumpBufferEnc3("RGB", colorFXRGB);
    printf("\n");
    colorFXRGB.lerp       (rgbBlack, rgbMax, 100); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.rotateLeft (                     ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.rotateLeft (                     ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.rotateLeft (                     ); dumpBufferEnc3("RGB", colorFXRGB);
    colorFXRGB.rotateLeft (                     ); dumpBufferEnc3("RGB", colorFXRGB);
    printf("\n");
    _DIVIDERLINE_DASHSTR_NL2();
    colorFXRGBRawRGB.lerp       (rgbBlack, rgbMax, 100); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.shiftRight (rgbBlack             ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.shiftRight (rgbBlack             ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.shiftRight (rgbBlack             ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.shiftRight (rgbBlack             ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    printf("\n");
    colorFXRGBRawRGB.lerp       (rgbBlack, rgbMax, 100); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.shiftLeft  (rgbBlack             ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.shiftLeft  (rgbBlack             ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.shiftLeft  (rgbBlack             ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.shiftLeft  (rgbBlack             ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    printf("\n");
    colorFXRGBRawRGB.lerp       (rgbBlack, rgbMax, 100); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.rotateRight(                     ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.rotateRight(                     ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.rotateRight(                     ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.rotateRight(                     ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    printf("\n");
    colorFXRGBRawRGB.lerp       (rgbBlack, rgbMax, 100); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.rotateLeft (                     ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.rotateLeft (                     ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.rotateLeft (                     ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    colorFXRGBRawRGB.rotateLeft (                     ); dumpBufferRaw3("RGB", colorFXRGBRawRGB);
    printf("\n");
    _DIVIDERLINE_DASHSTR_NL1();
    _DIVIDERLINE_DASHSTR_NL1();
    _DIVIDERLINE_DASHSTR_NL2();



    typedef eCxx::ColorFX1D<eCxx::WColor, 5> WColor5;

    WColor5 wColor;
    wColor.set( 0, eCxx::WColor(1) );
    wColor.set( 1, eCxx::WColor(2) );
    wColor.set( 2, eCxx::WColor(3) );
    wColor.set( 3, eCxx::WColor(4) );
    wColor.set( 4, eCxx::WColor(5) );

    for(WColor5::ConstIterator it = wColor.cbegin(); it != wColor.cend(); ++it) printf( "%d ", (int) it->w() );
    printf("\n");
    for(WColor5::ConstReverseIterator it = wColor.crbegin(); it != wColor.crend(); ++it) printf( "%d ", (int) it->w() );
    printf("\n");
    printf("\n");
    _DIVIDERLINE_DASHSTR_NL1();
    _DIVIDERLINE_DASHSTR_NL1();
    _DIVIDERLINE_DASHSTR_NL2();



    eCxx::ColorFX1D<eCxx::RGBColor, 8, eCxx::CBP::RawBuffer> rgbRaw8;

    rgbRaw8.set(eCxx::Ext::RGB::black);
    rgbRaw8.lerpG( eCxx::HSVColor(120, 200, 200), eCxx::HSVColor(120, 0, 200) );
    dumpBufferRaw3("RGB", rgbRaw8);

    rgbRaw8.set(eCxx::Ext::RGB::black);
    rgbRaw8.lerpG<eCxx::HSVColor::S>( eCxx::HSVColor(120, 200, 200), eCxx::HSVColor(120, 0, 200) );
    dumpBufferRaw3("RGB", rgbRaw8);

    _DIVIDERLINE_DASHSTR_NL1();
    _DIVIDERLINE_DASHSTR_NL1();
    _DIVIDERLINE_DASHSTR_NL2();



    eCxx::ColorFX1D<eCxx::RGBColor, 16, eCxx::CBP::RawBuffer> dstRaw;
    eCxx::ColorFX1D<eCxx::RGBColor,  3, eCxx::CBP::RawBuffer> sprRaw;
    dstRaw.set( eCxx::Ext::RGB::black );
    sprRaw.set( eCxx::RGBColor(1, 2, 3) );

    eCxx::ColorFX1D<eCxx::RGBColor, 16, eCxx::CBP::EncapsulatedBuffer> dstEnc;
    eCxx::ColorFX1D<eCxx::RGBColor,  3, eCxx::CBP::EncapsulatedBuffer> sprEnc;
    dstEnc.set( eCxx::Ext::RGB::black );
    sprEnc.set( eCxx::RGBColor(4, 5, 6) );

    dstRaw.put(-1, sprRaw);
    dstRaw.put( 5, sprRaw);
    dstRaw.put(15, sprEnc);
    dumpBufferRaw3Sum("RGB", dstRaw);
    printf("\n");

    dstEnc.put(-1, sprEnc);
    dstEnc.put( 5, sprEnc);
    dstEnc.put(15, sprRaw);
    dumpBufferEnc3Sum("RGB", dstEnc);
    printf("\n");



    return 0;
}
