/*
 * 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.
 *
 */

// @todo : prendre en compte l'endianess... (faire deux fichiers : ConvertPixelBigEndian.inl et ConvertPixelLittleEndian.inl)


// Specialization for conversions PXF_L8 -> ???
template <>
inline void ConvertPixel<PXF_L8, PXF_L8>(const uchar* pSrc, uchar* pDest)
{
    *pDest = *pSrc;
}

template <>
inline void ConvertPixel<PXF_L8, PXF_A8L8>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = *pSrc;
    pDest[1] = 0xFF;
}

template <>
inline void ConvertPixel<PXF_L8, PXF_A1R5G5B5>(const uchar* pSrc, uchar* pDest)
{
    *reinterpret_cast<ushort*>(pDest) = 0x8000 |
                                               ((*pSrc >> 3) << 10) |
                                               ((*pSrc >> 3) <<  5) |
                                               ((*pSrc >> 3) <<  0);
}

template <>
inline void ConvertPixel<PXF_L8, PXF_A4R4G4B4>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = (*pSrc & 0xF0) | (*pSrc >> 4);
    pDest[1] = 0xF0 | (*pSrc >> 4);
}

template <>
inline void ConvertPixel<PXF_L8, PXF_R8G8B8>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = *pSrc;
    pDest[1] = *pSrc;
    pDest[2] = *pSrc;
}

template <>
inline void ConvertPixel<PXF_L8, PXF_A8R8G8B8>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = *pSrc;
    pDest[1] = *pSrc;
    pDest[2] = *pSrc;
    pDest[3] = 0xFF;
}


// Specialization for conversions PXF_A8L8 -> ???
template <>
inline void ConvertPixel<PXF_A8L8, PXF_L8>(const uchar* pSrc, uchar* pDest)
{
    *pDest = pSrc[0];
}

template <>
inline void ConvertPixel<PXF_A8L8, PXF_A8L8>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = pSrc[0];
    pDest[1] = pSrc[1];
}

template <>
inline void ConvertPixel<PXF_A8L8, PXF_A1R5G5B5>(const uchar* pSrc, uchar* pDest)
{
    *reinterpret_cast<ushort*>(pDest) = ((pSrc[1] >> 7) << 15) |
                                               ((pSrc[0] >> 3) << 10) |
                                               ((pSrc[0] >> 3) <<  5) |
                                               ((pSrc[0] >> 3) <<  0);
}

template <>
inline void ConvertPixel<PXF_A8L8, PXF_A4R4G4B4>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = (pSrc[0] & 0xF0) | (pSrc[0] >> 4);
    pDest[1] = (pSrc[1] & 0xF0) | (pSrc[0] >> 4);
}

template <>
inline void ConvertPixel<PXF_A8L8, PXF_R8G8B8>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = pSrc[0];
    pDest[1] = pSrc[0];
    pDest[2] = pSrc[0];
}

template <>
inline void ConvertPixel<PXF_A8L8, PXF_A8R8G8B8>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = pSrc[0];
    pDest[1] = pSrc[0];
    pDest[2] = pSrc[0];
    pDest[3] = pSrc[1];
}


// Specialization for conversions PXF_A1R5G5B5 -> ???
template <>
inline void ConvertPixel<PXF_A1R5G5B5, PXF_L8>(const uchar* pSrc, uchar* pDest)
{
    ushort Pix = *reinterpret_cast<const ushort*>(pSrc);
    *pDest = static_cast<uchar>(((Pix & 0x7C00) >> 7) * 0.30 +
                                       ((Pix & 0x03E0) >> 2) * 0.59 +
                                       ((Pix & 0x001F) << 3) * 0.11);
}

template <>
inline void ConvertPixel<PXF_A1R5G5B5, PXF_A8L8>(const uchar* pSrc, uchar* pDest)
{
    ushort Pix = *reinterpret_cast<const ushort*>(pSrc);
    pDest[0] = static_cast<uchar>(((Pix & 0x7C00) >> 7) * 0.30 +
                                         ((Pix & 0x03E0) >> 2) * 0.59 +
                                         ((Pix & 0x001F) << 3) * 0.11);
    pDest[1] = pSrc[1] & 0x8000 ? 0xFF : 0x00;
}

template <>
inline void ConvertPixel<PXF_A1R5G5B5, PXF_A1R5G5B5>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = pSrc[0];
    pDest[1] = pSrc[1];
}

template <>
inline void ConvertPixel<PXF_A1R5G5B5, PXF_A4R4G4B4>(const uchar* pSrc, uchar* pDest)
{
    ushort Pix = *reinterpret_cast<const ushort*>(pSrc);
    pDest[1] = (Pix & 0x8000 ? 0xF0 : 0x00) | ((Pix & 0x7C00) >> 11);
    pDest[0] = ((Pix & 0x03C0) >> 2) | ((Pix & 0x001F) >> 1);
}

template <>
inline void ConvertPixel<PXF_A1R5G5B5, PXF_R8G8B8>(const uchar* pSrc, uchar* pDest)
{
    ushort Pix = *reinterpret_cast<const ushort*>(pSrc);
    pDest[2] = (Pix & 0x7C00) >> 7;
    pDest[1] = (Pix & 0x03E0) >> 2;
    pDest[0] = (Pix & 0x001F) << 3;
}

template <>
inline void ConvertPixel<PXF_A1R5G5B5, PXF_A8R8G8B8>(const uchar* pSrc, uchar* pDest)
{
    ushort Pix = *reinterpret_cast<const ushort*>(pSrc);
    pDest[3] = (Pix & 0x8000) >> 8;
    pDest[2] = (Pix & 0x7C00) >> 7;
    pDest[1] = (Pix & 0x03E0) >> 2;
    pDest[0] = (Pix & 0x001F) << 3;
}

// Specialization for conversions PXF_A4R4G4B4 -> ???
template <>
inline void ConvertPixel<PXF_A4R4G4B4, PXF_L8>(const uchar* pSrc, uchar* pDest)
{
    *pDest = static_cast<uchar>(((pSrc[1] & 0x0F) << 4) * 0.30 +
                                       ((pSrc[0] & 0xF0) >> 0) * 0.59 +
                                       ((pSrc[0] & 0x0F) << 4) * 0.11);
}

template <>
inline void ConvertPixel<PXF_A4R4G4B4, PXF_A8L8>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = static_cast<uchar>(((pSrc[1] & 0x0F) << 4) * 0.30 +
                                         ((pSrc[0] & 0xF0) >> 0) * 0.59 +
                                         ((pSrc[0] & 0x0F) << 4) * 0.11);
    pDest[1] = pSrc[1] & 0xF0;
}

template <>
inline void ConvertPixel<PXF_A4R4G4B4, PXF_A1R5G5B5>(const uchar* pSrc, uchar* pDest)
{
    *reinterpret_cast<ushort*>(pDest) = ((pSrc[1] & 0x80) <<  8) |
                                               ((pSrc[1] & 0x0F) << 11) |
                                               ((pSrc[0] & 0xF0) <<  2) |
                                               ((pSrc[0] & 0x0F) <<  1);
}

template <>
inline void ConvertPixel<PXF_A4R4G4B4, PXF_A4R4G4B4>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = pSrc[0];
    pDest[1] = pSrc[1];
}

template <>
inline void ConvertPixel<PXF_A4R4G4B4, PXF_R8G8B8>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = (pSrc[0] & 0x0F) << 4;
    pDest[1] = (pSrc[0] & 0xF0);
    pDest[2] = (pSrc[1] & 0x0F) << 4;
}

template <>
inline void ConvertPixel<PXF_A4R4G4B4, PXF_A8R8G8B8>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = (pSrc[0] & 0x0F) << 4;
    pDest[1] = (pSrc[0] & 0xF0);
    pDest[2] = (pSrc[1] & 0x0F) << 4;
    pDest[3] = (pSrc[1] & 0xF0);
}


// Specialization for converdions PXF_R8G8B8 -> ???
template <>
inline void ConvertPixel<PXF_R8G8B8, PXF_L8>(const uchar* pSrc, uchar* pDest)
{
    *pDest = static_cast<uchar>(pSrc[2] * 0.30 + pSrc[1] * 0.59 + pSrc[0] * 0.11);
}

template <>
inline void ConvertPixel<PXF_R8G8B8, PXF_A8L8>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = static_cast<uchar>(pSrc[2] * 0.30 + pSrc[1] * 0.59 + pSrc[0] * 0.11);
    pDest[1] = 0xFF;
}

template <>
inline void ConvertPixel<PXF_R8G8B8, PXF_A1R5G5B5>(const uchar* pSrc, uchar* pDest)
{
    *reinterpret_cast<ushort*>(pDest) = 0x8000 |
                                               ((pSrc[2] >> 3) << 10) |
                                               ((pSrc[1] >> 3) <<  5) |
                                               ((pSrc[0] >> 3) <<  0);
}

template <>
inline void ConvertPixel<PXF_R8G8B8, PXF_A4R4G4B4>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = (pSrc[1] & 0xF0) | (pSrc[0] >> 4);
    pDest[1] = 0xF0 | (pSrc[2] >> 4);
}

template <>
inline void ConvertPixel<PXF_R8G8B8, PXF_R8G8B8>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = pSrc[0];
    pDest[1] = pSrc[1];
    pDest[2] = pSrc[2];
}

template <>
inline void ConvertPixel<PXF_R8G8B8, PXF_A8R8G8B8>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = pSrc[0];
    pDest[1] = pSrc[1];
    pDest[2] = pSrc[2];
    pDest[3] = 0xFF;
}


// Specialization for conversions PXF_A8R8G8B8 -> ???
template <>
inline void ConvertPixel<PXF_A8R8G8B8, PXF_L8>(const uchar* pSrc, uchar* pDest)
{
    *pDest = static_cast<uchar>(pSrc[2] * 0.30 + pSrc[1] * 0.59 + pSrc[0] * 0.11);
}

template <>
inline void ConvertPixel<PXF_A8R8G8B8, PXF_A8L8>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = static_cast<uchar>(pSrc[2] * 0.30 + pSrc[1] * 0.59 + pSrc[0] * 0.11);
    pDest[1] = pSrc[3];
}

template <>
inline void ConvertPixel<PXF_A8R8G8B8, PXF_A1R5G5B5>(const uchar* pSrc, uchar* pDest)
{
    *reinterpret_cast<ushort*>(pDest) = ((pSrc[3] >> 7) << 15) |
                                               ((pSrc[2] >> 3) << 10) |
                                               ((pSrc[1] >> 3) <<  5) |
                                               ((pSrc[0] >> 3) <<  0);
}

template <>
inline void ConvertPixel<PXF_A8R8G8B8, PXF_A4R4G4B4>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = (pSrc[1] & 0xF0) | (pSrc[0] >> 4);
    pDest[1] = (pSrc[3] & 0xF0) | (pSrc[2] >> 4);
}

template <>
inline void ConvertPixel<PXF_A8R8G8B8, PXF_R8G8B8>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = pSrc[0];
    pDest[1] = pSrc[1];
    pDest[2] = pSrc[2];
}

template <>
inline void ConvertPixel<PXF_A8R8G8B8, PXF_A8R8G8B8>(const uchar* pSrc, uchar* pDest)
{
    pDest[0] = pSrc[0];
    pDest[1] = pSrc[1];
    pDest[2] = pSrc[2];
    pDest[3] = pSrc[3];
}
