// This code is in the public domain -- castanyo@yahoo.es

#pragma once
#ifndef NV_IMAGE_COLORBLOCK_H
#define NV_IMAGE_COLORBLOCK_H

#include "nvmath/Color.h"
#include "nvmath/Vector.h"

namespace nv
{
    class Image;
    class FloatImage;


    /// Uncompressed 4x4 color block.
    struct ColorBlock
    {
        ColorBlock();
        ColorBlock(const uint * linearImage);
        ColorBlock(const ColorBlock & block);
        ColorBlock(const Image * img, uint x, uint y);

        void init(const Image * img, uint x, uint y);
        void init(uint w, uint h, const uint * data, uint x, uint y);
        void init(uint w, uint h, const float * data, uint x, uint y);

        void swizzle(uint x, uint y, uint z, uint w); // 0=r, 1=g, 2=b, 3=a, 4=0xFF, 5=0

        bool isSingleColor(Color32 mask = Color32(0xFF, 0xFF, 0xFF, 0x00)) const;
        bool hasAlpha() const;


        // Accessors
        const Color32 * colors() const;

        Color32 color(uint i) const;
        Color32 & color(uint i);

        Color32 color(uint x, uint y) const;
        Color32 & color(uint x, uint y);

    private:

        Color32 m_color[4*4];

    };


    /// Get pointer to block colors.
    inline const Color32 * ColorBlock::colors() const
    {
        return m_color;
    }

    /// Get block color.
    inline Color32 ColorBlock::color(uint i) const
    {
        nvDebugCheck(i < 16);
        return m_color[i];
    }

    /// Get block color.
    inline Color32 & ColorBlock::color(uint i)
    {
        nvDebugCheck(i < 16);
        return m_color[i];
    }

    /// Get block color.
    inline Color32 ColorBlock::color(uint x, uint y) const
    {
        nvDebugCheck(x < 4 && y < 4);
        return m_color[y * 4 + x];
    }

    /// Get block color.
    inline Color32 & ColorBlock::color(uint x, uint y)
    {
        nvDebugCheck(x < 4 && y < 4);
        return m_color[y * 4 + x];
    }

    /*
    struct ColorSet
    {
        ColorSet() : colorCount(0), indexCount(0), w(0), h(0) {}
        //~ColorSet() {}

        void allocate(uint w, uint h);

        void setColors(const float * data, uint img_w, uint img_h, uint img_x, uint img_y);
        void setColors(const Vector3 colors[16], const float weights[16]);
        void setColors(const Vector4 colors[16], const float weights[16]);

        void setAlphaWeights();
        void setUniformWeights();

        void createMinimalSet(bool ignoreTransparent);
        void wrapIndices();

        void swizzle(uint x, uint y, uint z, uint w); // 0=r, 1=g, 2=b, 3=a, 4=0xFF, 5=0

        bool isSingleColor(bool ignoreAlpha) const;
        bool hasAlpha() const;

        // These methods require indices to be set:
        Vector4 color(uint x, uint y) const { nvDebugCheck(x < w && y < h); return colors[indices[y * 4 + x]]; }
        Vector4 & color(uint x, uint y) { nvDebugCheck(x < w && y < h); return colors[indices[y * 4 + x]]; }

        Vector4 color(uint i) const { nvDebugCheck(i < indexCount); return colors[indices[i]]; }
        Vector4 & color(uint i) { nvDebugCheck(i < indexCount); return colors[indices[i]]; }

        float weight(uint i) const { nvDebugCheck(i < indexCount); return weights[indices[i]]; }

        bool isValidIndex(uint i) const { return i < indexCount && indices[i] >= 0; }

        uint colorCount;
        uint indexCount;    // Fixed to 16
        uint w, h;          // Fixed to 4x4

        // Allocate color set dynamically and add support for sets larger than 4x4.
        Vector4 colors[16];
        float weights[16];  // @@ Add mask to indicate what color components are weighted?
        int indices[16];
    };
    */


    /// Uncompressed 4x4 alpha block.
    struct AlphaBlock4x4
    {
        void init(uint8 value);
        void init(const ColorBlock & src, uint channel);
        //void init(const ColorSet & src, uint channel);

        //void initMaxRGB(const ColorSet & src, float threshold);
        //void initWeights(const ColorSet & src);

        uint8 alpha[4*4];
        float weights[16];
    };


    struct FloatAlphaBlock4x4
    {
        float alphas[4 * 4];
        float weights[4 * 4];
    };

    struct FloatColorBlock4x4
    {
        Vector4 colors[4 * 4];
        float weights[4 * 4];
    };



} // nv namespace

#endif // NV_IMAGE_COLORBLOCK_H
