/*
 * This source file is part of KEOS (Free 3D Engine)
 * For the latest info, see http://www.keosengine.org/
 * E-mails : thierry.vouriot@keosengine.org, yeri@keosengine.org
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place - Suite 330, Boston, MA 02111-1307, USA, or go to
 * http://www.gnu.org/copyleft/lesser.txt.
 *
 */

#ifndef KEOS_PIXELUTILS_H
#define KEOS_PIXELUTILS_H

#include "KeosPrerequisites.h"
#include "KeosLogger.h"

namespace Keos
{

    /** Return the number of bytes per pixel / pixel format.
     *  @param Format Pixel format.
     *  @return Number of bytes per pixel.
     */
    inline uint GetBytesPerPixel(TPixelFormat Format)
    {
        switch (Format)
        {
            case PXF_L8 :       return 1;
            case PXF_A8L8 :     return 2;
            case PXF_A1R5G5B5 : return 2;
            case PXF_A4R4G4B4 : return 2;
            case PXF_R8G8B8 :   return 3;
            case PXF_A8R8G8B8 : return 4;
            case PXF_DXTC1 :    return 1;
            case PXF_DXTC3 :    return 2;
            case PXF_DXTC5 :    return 2;
            default :           return 0;
        }
    }

    /** Return the name of a pixel format.
     *  @param Format Pixel format.
     *  @return String with the format name.
     */
    inline String FormatToString(TPixelFormat Format)
    {
        switch (Format)
        {
            case PXF_L8 :       return "PXF_L8";
            case PXF_A8L8 :     return "PXF_A8L8";
            case PXF_A1R5G5B5 : return "PXF_A1R5G5B5";
            case PXF_A4R4G4B4 : return "PXF_A4R4G4B4";
            case PXF_R8G8B8 :   return "PXF_R8G8B8";
            case PXF_A8R8G8B8 : return "PXF_A8R8G8B8";
            case PXF_DXTC1 :    return "PXF_DXTC1";
            case PXF_DXTC3 :    return "PXF_DXTC3";
            case PXF_DXTC5 :    return "PXF_DXTC5";
            default :           return "Unknown format";
        }
    }

    /** Test if a format is compressed.
     *  @param Format Pixel format.
     *  @return True if the format is compressed.
     */
    inline bool FormatCompressed(TPixelFormat Format)
    {
        switch (Format)
        {
            case PXF_DXTC1 :
            case PXF_DXTC3 :
            case PXF_DXTC5 :
                return true;

            default :
                return false;
        }
    }

    /** Calculate the number of mipmapping levels for a dimension.
     *  @param nWidth Texture width.
     *  @param nHeight Texture height.
     *  @return Maximum number of mipmapping levels.
     */
    inline int GetNbMipLevels(int nWidth, int nHeight)
    {
        int nCount = 0;

        while ((nWidth > 1) || (nHeight > 1))
        {
            if (nWidth > 1)  nWidth  /= 2;
            if (nHeight > 1) nHeight /= 2;
            ++nCount;
        }

        return nCount;
    }

    /** Convert a pixel from a format to another.
     *  @param pSrc Pixel to be converted.
     *  @param pDest Result of the conversion. 
     */
    template <TPixelFormat SrcFmt, TPixelFormat DestFmt>
    inline void ConvertPixel(const uchar* pSrc, uchar* pDest)
    {
        UNSUPPORTED_EXCEPT(String("Software conversion of pixel format (") +
                           FormatToString(SrcFmt) +
                           " -> " +
                           FormatToString(DestFmt) +
                           ")", "ConvertPixel");
    }

    // Functions of converion for each couple of formats
    #include "KeosConvertPixel.inl"


    /** Convert a pixel from a format to another.
     *  @param SrcFmt Source format.
     *  @param pSrc Pixel to be converted.
     *  @param DestFmt Destination format.
     *  @param pDest Result of the conversion. 
     */
    inline void ConvertPixel(TPixelFormat SrcFmt, const uchar* pSrc, TPixelFormat DestFmt, uchar* pDest)
    {
        #define CONVERSIONS_FOR(Fmt) \
            case Fmt : \
            { \
                switch (DestFmt) \
                { \
                    case PXF_L8 :       ConvertPixel<Fmt, PXF_L8>(pSrc, pDest);       break; \
                    case PXF_A8L8 :     ConvertPixel<Fmt, PXF_A8L8>(pSrc, pDest);     break; \
                    case PXF_A1R5G5B5 : ConvertPixel<Fmt, PXF_A1R5G5B5>(pSrc, pDest); break; \
                    case PXF_A4R4G4B4 : ConvertPixel<Fmt, PXF_A4R4G4B4>(pSrc, pDest); break; \
                    case PXF_R8G8B8 :   ConvertPixel<Fmt, PXF_R8G8B8>(pSrc, pDest);   break; \
                    case PXF_A8R8G8B8 : ConvertPixel<Fmt, PXF_A8R8G8B8>(pSrc, pDest); break; \
                    case PXF_DXTC1 :    ConvertPixel<Fmt, PXF_DXTC1>(pSrc, pDest);    break; \
                    case PXF_DXTC3 :    ConvertPixel<Fmt, PXF_DXTC3>(pSrc, pDest);    break; \
                    case PXF_DXTC5 :    ConvertPixel<Fmt, PXF_DXTC5>(pSrc, pDest);    break; \
                } \
                break; \
            }

        switch (SrcFmt)
        {
            CONVERSIONS_FOR(PXF_L8)
            CONVERSIONS_FOR(PXF_A8L8)
            CONVERSIONS_FOR(PXF_A1R5G5B5)
            CONVERSIONS_FOR(PXF_A4R4G4B4)
            CONVERSIONS_FOR(PXF_R8G8B8)
            CONVERSIONS_FOR(PXF_A8R8G8B8)
            CONVERSIONS_FOR(PXF_DXTC1)
            CONVERSIONS_FOR(PXF_DXTC3)
            CONVERSIONS_FOR(PXF_DXTC5)
        }

        #undef CONVERIONS_FOR
    }

} // namespace Keos

#endif // KEOS_PIXELUTILS_H