/*==============================================================================
	Copyright (C) 2008 IT Access.,Co.Ltd. All Rights Reserved.
	
	This software is the confidential and proprietary information 
	of IT Access.,Co.Ltd.
	
	Note:

==============================================================================*/

/*==============================================================================
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> INCLUDE. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
==============================================================================*/
#include "GealCommon.h"
#include "GealTypes.h"
#include "GealAPI.h"
#include "GealConfigAPI.h"
#include "GealUtilAPI.h"
#include "GealFigureAPI.h"
#include "GealStringAPI.h"
#include "GealTimerAPI.h"
#include "GealTargetAPI.h"

#include "TargetTypes.h"

#if defined (TARGET_COLOR_CLUT8) || defined (TARGET_COLOR_CLUT4) || defined (TARGET_COLOR_MONO)

/*==============================================================================
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> CONFIGURATION. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
==============================================================================*/
//#define GETLINE(p, y)	((TARGET_COLOR*)(((GE_UINT8*)((p)->pBits)) + (p)->dwLineByte * (y)))
#define GETLINE(p, y)	((TARGET_COLOR*)(((GE_UINT8*)(0x80ff0000)) + 512 * (y)))


#if defined (TARGET_COLOR_CLUT8)
	void SETCOLOR(TARGET* p, int x, int y, GE_COLOR val)
	{
		TARGET_COLOR*	pBits = GETLINE(p, y) + x;
		*pBits = (TARGET_COLOR)val;
	}
#elif defined (TARGET_COLOR_CLUT4)
	void SETCOLOR(TARGET* p, int x, int y, GE_COLOR val)
	{
		TARGET_COLOR*	pBits = GETLINE(p, y) + x/2;

		if (x & 0x01)
		{
			/* LSB */
			*pBits &= 0xF0;
			*pBits |= (val & 0x0F);
		}
		else
		{
			/* MSB */
			*pBits &= 0x0F;
			*pBits |= (val & 0x0F) << 4;
		}
	}
#elif defined (TARGET_COLOR_MONO)
	void SETCOLOR(TARGET* p, int x, int y, GE_COLOR val)
	{
		TARGET_COLOR*	pBits = GETLINE(p, y) + x/8;
		TARGET_COLOR	mask;
		GE_INT			pos;

		pos  = x & 0x07;
		mask = (0x80 >> pos);

		*pBits &= ~mask;
		*pBits |= (val) ? mask : 0;
	}
#endif

/*==============================================================================
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> TYPE. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
==============================================================================*/

/*==============================================================================
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> MEMBER. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
==============================================================================*/

/*==============================================================================
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROCEDURE. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
==============================================================================*/

/*------------------------------------------------------------------------------
	This API draws a pixel.
------------------------------------------------------------------------------*/
GE_VOID UGxDrawPixel(HTARGET  hTarget, 
					 GE_INT   x,
					 GE_INT   y,
					 GE_COLOR crColor)
{
	TARGET*			pTarget;

	if (GE_NULL == hTarget)
		return;

	if (UGxIsTransColor(crColor))
		return;

	pTarget = (TARGET*)hTarget;
	if ((x < 0 || x >= pTarget->wX) || 
		(y < 0 || y >= pTarget->wY))
		return;

	SETCOLOR(pTarget, x, y, crColor);
}

/*------------------------------------------------------------------------------
	This API draws a horizontal or vertical line.
		nType	0 : horizontal line
				1 : vertical line
------------------------------------------------------------------------------*/
GE_VOID UGxDrawLineHV(
	HTARGET					hTarget,
	GE_INT					nX,
	GE_INT					nY,
	GE_INT					nType,
	GE_INT					nLength,
	GE_COLOR				crColor
	)
{
	/* Draws only horizontal & vertical line by user. */
	TARGET*			pTarget;
	GE_INT			i;
	GE_INT			length;
	GE_INT			nEnd;

	if (GE_NULL == hTarget)
		return;

	if (UGxIsTransColor(crColor))
		return ;

	pTarget = (TARGET*)hTarget;

	if (nType == 0)
	{
		/* Horizontal line. */

		if (nY<0 || nY>=pTarget->wY)
			return ;

		nEnd = nX + nLength;
		if (nX > nEnd)
			GE_SWAP(nX, nEnd);
		nX = GE_MAX(nX, 0);
		nEnd = GE_MIN(nEnd, pTarget->wX);
		length = GE_MAX(nEnd - nX, 0);

		for (i=0; i<length; i++)
		{
			SETCOLOR(pTarget, nX+i, nY, crColor);
		}
	}
	else if (nType == 1)
	{
		/* Vertical line. */

		if (nX<0 || nX>=pTarget->wX)
			return ;

		nEnd = nY + nLength;
		if (nY > nEnd)
			GE_SWAP(nY, nEnd);
		nY = GE_MAX(nY, 0);
		nEnd = GE_MIN(nEnd, pTarget->wY);
		length = GE_MAX(nEnd - nY, 0);

		for (i=0; i<length; i++)
		{
			SETCOLOR(pTarget, nX, nY+i, crColor);
		}
	}
}


/*------------------------------------------------------------------------------
	This API draws a rectangle.
------------------------------------------------------------------------------*/
GE_VOID UGxDrawRectangle(HTARGET  hTarget,
						 GE_INT   left,
						 GE_INT   top,
						 GE_INT   right,
						 GE_INT   bottom,
						 GE_COLOR crColor,
						 GE_INT   nType)
{
	TARGET*			pTarget;
	GE_INT			x, y;

	if (GE_NULL == hTarget)
		return;

	if (UGxIsTransColor(crColor))
		return;

	pTarget = (TARGET*)hTarget;

	if (top > bottom || left > right)
		return;

	top    = GE_MINMAX(top,    0, pTarget->wY-1);
	left   = GE_MINMAX(left,   0, pTarget->wX-1);
	right  = GE_MINMAX(right,  0, pTarget->wX);
	bottom = GE_MINMAX(bottom, 0, pTarget->wY);

	if (nType == 0)
	{
		/* top */
		for (x=left; x<right; x++) 
		{
			SETCOLOR(pTarget, x, top, crColor);
		}
			
		if (bottom > 0)
		{
			/* left,right */
			for (y=top+1; y<bottom-1; y++)
			{
				SETCOLOR(pTarget, left,    y, crColor);
				SETCOLOR(pTarget, right-1, y, crColor);
			}

			/* bottom */
			for (x=left; x<right; x++) 
			{
				SETCOLOR(pTarget, x, bottom-1, crColor);
			}
		}
	}
	else
	{
		/* fill */
		for (y=top; y<bottom; y++)
		{
			for (x=left; x<right; x++) 
			{
				SETCOLOR(pTarget, x, y, crColor);
			}
		}
	}
}

/*------------------------------------------------------------------------------
	This API draws a bitmap.
------------------------------------------------------------------------------*/
GE_VOID UGxDrawBitmap(HTARGET          hTarget,
					  GE_INT           nX,
					  GE_INT           nY,
					  const GE_BITMAP* pBitmap,
					  const GE_RECT*   prcClip)
{
	TARGET*			pTarget;
	GE_INT			k, w, h;
	GE_INT32		linebyte;
	GE_INT			top, left, right, bottom;
	GE_INT			offs_x, offs_y;
	GE_INT			x, y;

	if ((GE_NULL == hTarget) || (GE_NULL == pBitmap))
		return;

	pTarget = (TARGET*)hTarget;

	w = pBitmap->wWidth;
	h = pBitmap->wHeight;
	linebyte = pBitmap->lwLinebyte;

	top    = GE_MINMAX(nY,   0, pTarget->wY-1);
	left   = GE_MINMAX(nX,   0, pTarget->wX-1);
	right  = GE_MINMAX(nX+w, 0, pTarget->wX);
	bottom = GE_MINMAX(nY+h, 0, pTarget->wY);

	if (prcClip)
	{
		top    = GE_MINMAX(top,    prcClip->top,  prcClip->bottom);
		left   = GE_MINMAX(left,   prcClip->left, prcClip->right);
		right  = GE_MINMAX(right,  prcClip->left, prcClip->right);
		bottom = GE_MINMAX(bottom, prcClip->top,  prcClip->bottom);
	}

	offs_x = GE_MAX(0, left - nX);
	offs_y = GE_MAX(0, top  - nY);

	if (pBitmap->cMode == eGECS_MONO)
	{
		const GE_UINT8*	sp;
		const GE_UINT8*	sline;

        sline  = pBitmap->pPxls;
		sline += linebyte * offs_y;

		for (y=top; y<bottom; y++)
		{
			GE_UINT8 mask;

			sp    = sline + offs_x / 8;
			k     = offs_x % 8;

			mask = (GE_UINT8)(0x80 >> k);

			for (x=left; x<right; x++) 
			{
				int dat = (*sp & mask) ? 1 : 0;

				SETCOLOR(pTarget, x, y, dat);

				mask >>= 1;
				if (mask == 0)
				{
					sp++;
					mask = 0x80;
				}
			}

			sline += linebyte;
		}
	}
	else if (pBitmap->cMode == eGECS_CLUT4)
	{
		const GE_UINT8*	sp;
		const GE_UINT8*	sline;

		sline  = pBitmap->pPxls;
		sline += linebyte * offs_y;

		for (y=top; y<bottom; y++)
		{
			GE_UINT8 mask;

			sp    = sline + offs_x / 2;
			k     = (offs_x % 2) * 4;

			mask = (GE_UINT8)(0xf0 >> k);

			for (x=left; x<right; x++) 
			{
				int dat = (mask == 0xf0)?((*sp & mask) >> 4):(*sp & mask);

				SETCOLOR(pTarget, x, y, dat);

				mask >>= 4;
				if (mask == 0)
				{
					sp++;
					mask = 0xf0;
				}
			}

			sline += linebyte;
		}
	}
	else if (pBitmap->cMode == eGECS_CLUT8) 
	{
		const GE_UINT8*	sp;
		const GE_UINT8*	sline;

		sline  = pBitmap->pPxls;
		sline += linebyte * offs_y;

		for (y=top; y<bottom; y++)
		{
			sp    = sline + offs_x;

			for (x=left; x<right; x++, sp++) 
			{
				if (GE_FALSE == UGxIsTransColor(*sp))
					SETCOLOR(pTarget, x, y, *sp);
			}

			sline += linebyte;
		}
	}
}

/*------------------------------------------------------------------------------
	This API draws a single font character.
------------------------------------------------------------------------------*/
GE_VOID UGxDrawFont(HTARGET        hTarget,
					GE_INT         nX,
					GE_INT         nY,
					const GE_FONT* pFont,
					GE_INT         nIndex,
					GE_INT         nOffset,
					GE_INT         nWidth,
					GE_COLOR       crColor,
					const GE_RECT* prcClip)
{
	TARGET*			pTarget;
	const GE_UINT8*	sp;
	const GE_UINT8*	sline;
	GE_INT			k, w, h;
	GE_INT32		linebyte;
	GE_INT			top, left, right, bottom;
	GE_INT			offs_x, offs_y;
	GE_INT			x, y;

	if ((GE_NULL == hTarget) || (GE_NULL == pFont))
		return;

	if (UGxIsTransColor(crColor))
		return;

	pTarget = (TARGET*)hTarget;

	w = GE_MIN(pFont->wWidth, nWidth);
	h = pFont->wHeight;

	top    = GE_MINMAX(nY,   0, pTarget->wY);
	left   = GE_MINMAX(nX,   0, pTarget->wX);
	right  = GE_MINMAX(nX+w, 0, pTarget->wX);
	bottom = GE_MINMAX(nY+h, 0, pTarget->wY);

	if (prcClip)
	{
		top    = GE_MINMAX(top,    prcClip->top,  prcClip->bottom);
		left   = GE_MINMAX(left,   prcClip->left, prcClip->right);
		right  = GE_MINMAX(right,  prcClip->left, prcClip->right);
		bottom = GE_MINMAX(bottom, prcClip->top,  prcClip->bottom);
	}

	offs_x = left - nX + nOffset;
	offs_y = top  - nY;

	if (pFont->wDepth == 1)
		linebyte = (pFont->wWidth + 7) >> 3;
	else
		return;

	sline = pFont->pBits + linebyte * pFont->wHeight * nIndex;
	sline += linebyte * offs_y;

	for (y=top; y<bottom; y++)
	{
		GE_UINT8 mask;

		sp   = sline + offs_x / 8;
		k    = offs_x % 8;
		mask = (GE_UINT8)(0x80 >> k);

		for (x=left; x<right; x++) 
		{
			if (*sp & mask)
			{
				SETCOLOR(pTarget, x, y, crColor);
			}

			mask >>= 1;
			if (mask == 0)
			{
				sp++;
				mask = 0x80;
			}
		}

		sline += linebyte;
	}
}

/*------------------------------------------------------------------------------
	This API clears rectangle.
------------------------------------------------------------------------------*/
GE_VOID UGxClearRectangle(HTARGET  hTarget,
						  GE_INT   left,
						  GE_INT   top,
						  GE_INT   right,
						  GE_INT   bottom)
{
	if (GE_NULL == hTarget)
		return;

	UGxDrawRectangle(hTarget,
					 left,
					 top,
					 right,
					 bottom,
					 0,
					 1);
}

/*------------------------------------------------------------------------------
	This API redraws current target.
------------------------------------------------------------------------------*/
GE_VOID UGxTargetRedraw(HTARGET  hTarget,
						GE_RECT* psRect)
{
/* Redraw しないので、とりあえずコメント
	TARGET*			pTarget;

	if (GE_NULL == hTarget)
		return;

	pTarget = (TARGET*)hTarget;

	if (psRect)
	{
		RECT			rc;
	
		rc.top    = psRect->top;
		rc.left   = psRect->left;
		rc.right  = psRect->right;
		rc.bottom = psRect->bottom;
		InvalidateRect(pTarget->hWnd, &rc, FALSE);
	}
	else
	{
		InvalidateRect(pTarget->hWnd, NULL, FALSE);
	}
*/
}

/*------------------------------------------------------------------------------
	This API gets if the color is tanslate or not.
------------------------------------------------------------------------------*/
GE_BOOL UGxIsTransColor(GE_COLOR crColor)
{
	const GE_COLOR*	pSysPalette;

	if (crColor & GE_TRANSPARENT_COLOR)
		return GE_TRUE;

	pSysPalette = GxSysPaletteGet();

#if   defined (TARGET_COLOR_CLUT8)
	crColor &= 0xFF;
#elif defined (TARGET_COLOR_CLUT4)
	crColor &= 0x0F;
#endif

	return (pSysPalette[crColor] & 0xFF000000) ? GE_TRUE : GE_FALSE;
}

/*------------------------------------------------------------------------------
	This API gets the alpha blending value.
------------------------------------------------------------------------------*/
GE_INT UGxGetBlend(GE_COLOR crColor)
{
	return (GE_TRUE == UGxIsTransColor(crColor)) ? 100 : 0;
}

#endif	
