#include <memory.h>
#include "MPixelFormatDescriptor.h"

// Formatos de pixel comunes
MPixelFormatDescriptor CommonPixelDescriptors[E_NCOMMON]=
{
  //m_uBPP;m_uRMask;m_uGMask;m_uBMask;m_uAMask;m_uRShiftLeft;m_uGShiftLeft;m_uBShiftLeft;m_uAShiftLeft;m_uRShiftRight;m_uGShiftRight;m_uBShiftRight;m_uAShiftRight;

	{  8, 0x00000000, 0x00000000, 0x00000000, 0x00000000,  0,  0,  0,  0,  8,  8,  8,  8 },	// Paletizado
	{ 16, 0x00007C00, 0x000003E0, 0x0000001F, 0x00000000, 10,  5,  0,  0,  3,  3,  3,  8 }, // 555
	{ 16, 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000, 11,  5,  0,  0,  3,  2,  3,  8 }, // 565
	{ 16, 0x00000F00, 0x000000F0, 0x0000000F, 0x0000F000,  8,  4,  0, 12,  4,  4,  4,  4 }, // 4444
	{ 24, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000, 16,  8,  0,  0,  0,  0,  0,  8 }, // 888 
  { 24, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000,  0,  8, 16,  0,  0,  0,  0,  8 }, // 888 BGR

	{ 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000, 16,  8,  0, 24,  0,  0,  0,  0 }, // ARGB32
	{ 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000, 16,  8,  0,  0,  0,  0,  0,  8 }, // 0RGB32
	{ 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000,  0,  8, 16,  0,  0,  0,  0,  8 }, // 0BGR32
  { 16, 0x00007C00, 0x000003E0, 0x0000001F, 0x80000000, 10,  5,  0,  0,  3,  3,  3,  8 }, // 1555  
};

// Funciones de streaming
void Output16Bit(unsigned char*& pDestiny, const unsigned uiPixel);
void Output24Bit(unsigned char*& pDestiny, const unsigned uiPixel);
void Output32Bit(unsigned char*& pDestiny, const unsigned uiPixel);
void Input16Bit (unsigned&        uiPixel, unsigned char*& pSource);
void Input24Bit (unsigned&		    uiPixel, unsigned char*& pSource);
void Input32Bit (unsigned&        uiPixel, unsigned char*& pSource);

#define PIXINPUT(NAME)  void (*NAME)(unsigned& uiPixel , unsigned char*& pSource     ) 
#define PIXOUTPUT(NAME) void (*NAME)(unsigned char*& pDestiny, const unsigned uiPixel) 

// Nombre      : MPixelFormatDescriptor::SetFrom()
// Parametros  : unsigned uBPP, unsigned uRMask, unsigned uGMask, unsigned uBMask, unsigned uAMask
// Retorno     : No
// Descripcion : Inicializa la estructura dados los bpp y las mascaras
void MPixelFormatDescriptor::SetFrom(unsigned uBPP, unsigned uRMask, unsigned uGMask, unsigned uBMask, unsigned uAMask)
{
	m_uBPP=uBPP;
	m_uRMask=uRMask;
	m_uGMask=uGMask;
	m_uBMask=uBMask;
	m_uAMask=uAMask;

	GetFromMask(m_uRShiftLeft, m_uRShiftRight, m_uRMask);
	GetFromMask(m_uGShiftLeft, m_uGShiftRight, m_uGMask);
	GetFromMask(m_uBShiftLeft, m_uBShiftRight, m_uBMask);
	GetFromMask(m_uAShiftLeft, m_uAShiftRight, m_uAMask);
	if (m_uAShiftRight==0)
	{
		m_uAShiftRight=m_uAShiftRight;
	}
}

// Nombre      : MPixelFormatDescriptor::operator==()
// Parametros  : MPixelFormatDescriptor& pfPixelFormatDescriptor
// Retorno     : 1: Si ; 0: No
// Descripcion : Operador igualdad entre estructuras
int	MPixelFormatDescriptor::operator==(MPixelFormatDescriptor& pfPixelFormatDescriptor)
{
	return (memcmp(this, &pfPixelFormatDescriptor, sizeof(MPixelFormatDescriptor))?0:1);
}

// Nombre      : MPixelFormatDescriptor::GetFromMask()
// Parametros  : unsigned int& uiShiftLeft, unsigned int& uiShiftRight, unsigned uiMask
// Retorno     : por parametro
// Descripcion : da los shifts dada una mascara. 
void MPixelFormatDescriptor::GetFromMask(unsigned int& uiShiftLeft, unsigned int& uiShiftRight, unsigned uiMask)
{
	unsigned i;
	int iState=0;

	unsigned uFirst=0;
	unsigned uLength=0;


	for (i=0 ; i<32 ; i++)
	{
		if (uiMask&(1<<i))
		{
			if (!iState)
			{
				uFirst=i;
				iState=1;
				uLength=1;
			}
			else
			{
				uLength++;
			}
		}
	}

	uiShiftLeft=uFirst;
	uiShiftRight=8-uLength;
}


// Nombre      : MPixelFormatDescriptor::ConvertARGBToARGB32()
// Parametros  : unsigned* puARGB32Destiny  , void* puLocalSource , unsigned uPixels
// Retorno     : No
// Descripcion : Convierte una rista de pixels a formato ARGB32
void MPixelFormatDescriptor::ConvertARGBToARGB32(unsigned* puARGB32Destiny  , void* puLocalSource , unsigned uPixels)
{
	unsigned i;
	unsigned uSource;
	unsigned uDestiny;
	unsigned char* pSource=(unsigned char*) puLocalSource;
	PIXINPUT(Input);

	switch (m_uBPP)
	{
	case 16:
		Input=Input16Bit;
		break;
	case 24:
		Input=Input24Bit;
		break;
	case 32:
		Input=Input32Bit;
		break;
	default:
		return;
	}
	
	if (m_uAShiftRight!=8)
	{
		for (i=0 ; i<uPixels ; i++)
		{
			Input(uSource, pSource);
			uDestiny=	(((uSource & m_uAMask) >> m_uAShiftLeft) << (24+m_uAShiftRight)) |
						(((uSource & m_uRMask) >> m_uRShiftLeft) << (16+m_uRShiftRight)) |
						(((uSource & m_uGMask) >> m_uGShiftLeft) << ( 8+m_uGShiftRight)) |
						(((uSource & m_uBMask) >> m_uBShiftLeft) << (   m_uBShiftRight));
			*(puARGB32Destiny++)=uDestiny;			
		}
	}
	else
	{
		for (i=0 ; i<uPixels ; i++)
		{
			Input(uSource, pSource);
			uDestiny=	( 0xFF000000												   ) |
						(((uSource & m_uRMask) >> m_uRShiftLeft) << (16+m_uRShiftRight)) |
						(((uSource & m_uGMask) >> m_uGShiftLeft) << ( 8+m_uGShiftRight)) |
						(((uSource & m_uBMask) >> m_uBShiftLeft) << (   m_uBShiftRight));
			*(puARGB32Destiny++)=uDestiny;			
		}
	}
}

// Nombre      : MPixelFormatDescriptor::ConvertARGBFromARGB32()
// Parametros  : void* puLocalDestiny	 , unsigned* puARGB32Source, unsigned uPixels
// Retorno     : No
// Descripcion : Convierte una rista de pixels en formato ARGB32 al formato de pixel definido por la estructura
void MPixelFormatDescriptor::ConvertARGBFromARGB32(void* puLocalDestiny	 , unsigned* puARGB32Source, unsigned uPixels)
{
	unsigned i;
	unsigned uSource;
	unsigned uDestiny;
	unsigned char* pDestiny=(unsigned char*) puLocalDestiny;
	PIXOUTPUT(Output);

	switch (m_uBPP)
	{
	case 16:
		Output=Output16Bit;
		break;
	case 24:
		Output=Output24Bit;
		break;
	case 32:
		Output=Output32Bit;
		break;
	default:
		return;
	}
	
	if (m_uAShiftRight!=8)
	{
		for (i=0 ; i<uPixels ; i++)
		{
			uSource=*(puARGB32Source++);
			uDestiny=
			(((uSource & 0xFF000000) >> (24+m_uAShiftRight))<< m_uAShiftLeft)|
			(((uSource & 0x00FF0000) >> (16+m_uRShiftRight))<< m_uRShiftLeft)|
			(((uSource & 0x0000FF00) >> ( 8+m_uGShiftRight))<< m_uGShiftLeft)|
			(((uSource & 0x000000FF) >> (	  m_uBShiftRight))<< m_uBShiftLeft);
			Output(pDestiny, uDestiny);			
		}
	}
	else
	{
		for (i=0 ; i<uPixels ; i++)
		{
			uSource=*(puARGB32Source++);
			uDestiny=
			(((uSource & 0x00FF0000) >> (16+m_uRShiftRight))<< m_uRShiftLeft)|
			(((uSource & 0x0000FF00) >> ( 8+m_uGShiftRight))<< m_uGShiftLeft)|
			(((uSource & 0x000000FF) >> (	  m_uBShiftRight))<< m_uBShiftLeft);
			Output(pDestiny, uDestiny);			
		}
	}
}

// Nombre      : Output16Bit()
// Parametros  : unsigned char*& pDestiny, const unsigned uiPixel
// Retorno     : No
// Descripcion : Pone 16 bits en el buffer de salida
void Output16Bit(unsigned char*& pDestiny, const unsigned uiPixel)
{
	*((unsigned short*)pDestiny)=uiPixel;		
	pDestiny+=2;
}

// Nombre      : Output24Bit()
// Parametros  : unsigned char*& pDestiny, const unsigned uiPixel
// Retorno     : No
// Descripcion : Pone 24 bits en el buffer de salida
void Output24Bit(unsigned char*& pDestiny, const unsigned uiPixel)
{
	pDestiny[0]=(uiPixel & 0xFF0000)>>16;
	pDestiny[1]=(uiPixel & 0xFF00)>>8;
  pDestiny[2]=uiPixel &  0xFF;	
	pDestiny+=3;
}

// Nombre      : Output32Bit()
// Parametros  : unsigned char*& pDestiny, const unsigned uiPixel
// Retorno     : No
// Descripcion : Pone 32 Bits en el buffer de salida
void Output32Bit(unsigned char*& pDestiny, const unsigned uiPixel)
{
	*((unsigned*)pDestiny)=uiPixel;	
	pDestiny+=4;
}

// Nombre      : Input16Bit()
// Parametros  : unsigned&	uiPixel, unsigned char*& pSource 
// Retorno     : No
// Descripcion : Lee 16 bits del buffer de entrada
void Input16Bit(unsigned&	uiPixel, unsigned char*& pSource)
{
	uiPixel=*((unsigned short*)pSource);		
	pSource+=2;
}

// Nombre      : Input24Bit()
// Parametros  : unsigned& uiPixel, unsigned char*& pSource 
// Retorno     : No
// Descripcion : Lee 24 bits del buffer de entrada
void Input24Bit(unsigned& uiPixel, unsigned char*& pSource)
{
	uiPixel=pSource[0]<<16 | ( pSource[1]<<8) | (pSource[2]);
	pSource+=3;
}

// Nombre      : Input32Bit()
// Parametros  : unsigned& uiPixel, unsigned char*& pSource 
// Retorno     : No
// Descripcion : Lee 32 bits del buffer de entrada
void Input32Bit(unsigned& uiPixel, unsigned char*& pSource)
{
	uiPixel=*((unsigned*)pSource);	
	pSource+=4;
}
