/* 
* classGraphics.cpp
*
* Created: 04/02/2020 21:26:32
* Author: Ledo
*/


#include "classGraphics.h"

// default constructor
classGraphics::classGraphics()
{
} //classGraphics

// default destructor
classGraphics::~classGraphics()
{
} //~classGraphics

//Internal call
void classGraphics::_swap(uint16_t *a, uint16_t *b)
{
	uint16_t tmp;
	tmp = *a;
	*a = *b;
	*b = tmp;
}

/*****************************************************************************
 * @name       :u32 mypow(uint8_t m,uint8_t n)
 * @date       :2018-08-09 
 * @function   :get the nth power of m (internal call)
 * @parameters :m:the multiplier
                n:the power
 * @retvalue   :the nth power of m
******************************************************************************/ 
uint32_t classGraphics::mypow(uint8_t m,uint8_t n)
{
	uint32_t result=1;	 
	while(n--)result*=m;    
	return result;
}

/*******************************************************************
 * @name       :void Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t color)
 * @date       :2018-08-09 
 * @function   :fill the specified area
 * @parameters :sx:the beginning x coordinate of the specified area
                sy:the beginning y coordinate of the specified area
				ex:the ending x coordinate of the specified area
				ey:the ending y coordinate of the specified area
				color:the filled color value
 * @retvalue   :None
********************************************************************/
void classGraphics::_fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t color)
{  	
	uint16_t i,j;			
	uint16_t width=ex-sx+1; 		
	uint16_t height=ey-sy+1;		
	Display.Tft_SetWindows(sx,sy,ex,ey);
	for(i=0;i<height;i++)
	{
		for(j=0;j<width;j++)
		Display.Tft_WR_DATA_16Bit(color);	 
	}
	Display.Tft_SetWindows(0,0,Display.lcddev.width-1,Display.lcddev.height-1);
}


/*******************************************************************
 * @name       :void DrawPoint(uint16_t x,uint16_t y,uint16_t color)
 * @date       :2020 02 05
 * @function   :draw a point in LCD screen
 * @parameters :x:the x coordinate of the point
                y:the y coordinate of the point
				color:the color value of the point
 * @retvalue   :None
********************************************************************/

void classGraphics::drawPoint(uint16_t x,uint16_t y,uint16_t color)
{
	Display.Tft_SetCursor(x,y);
	Display.Tft_WR_DATA_16Bit(color); 
}

/*******************************************************************
 * @name       :void DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
 * @date       :2020 02 05
 * @function   :Draw a line between two points
 * @parameters :x1:the beginning x coordinate of the line
                y1:the beginning y coordinate of the line
				x2:the ending x coordinate of the line
				y2:the ending y coordinate of the line
 * @retvalue   :None
********************************************************************/
void classGraphics::drawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
	uint16_t t; 
	int xerr=0,yerr=0,delta_x,delta_y,distance; 
	int incx,incy,uRow,uCol; 

	delta_x=x2-x1; 
	delta_y=y2-y1; 
	uRow=x1; 
	uCol=y1; 
	if(delta_x>0)incx=1; 
	else if(delta_x==0)incx=0;
	else {incx=-1;delta_x=-delta_x;} 
	if(delta_y>0)incy=1; 
	else if(delta_y==0)incy=0;
	else{incy=-1;delta_y=-delta_y;} 
	if( delta_x>delta_y)distance=delta_x; 
	else distance=delta_y; 
	for(t=0;t<=distance+1;t++ )
	{  
		drawPoint(uRow,uCol,color);
		xerr+=delta_x ; 
		yerr+=delta_y ; 
		if(xerr>distance) 
		{ 
			xerr-=distance; 
			uRow+=incx; 
		} 
		if(yerr>distance) 
		{ 
			yerr-=distance; 
			uCol+=incy; 
		} 
	}  
} 

/*****************************************************************************
 * @name       :void Draw_Triangle(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
 * @date       :2020 02 04
 * @function   :Draw a triangle at a specified position
 * @parameters :x0:the beginning x coordinate of the triangular edge 
                y0:the beginning y coordinate of the triangular edge 
				x1:the vertex x coordinate of the triangular
				y1:the vertex y coordinate of the triangular
				x2:the ending x coordinate of the triangular edge 
				y2:the ending y coordinate of the triangular edge 
 * @retvalue   :None
******************************************************************************/ 
void classGraphics::drawTriangle(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2, uint16_t color)
{
	drawLine(x0,y0,x1,y1,color);
	drawLine(x1,y1,x2,y2,color);
	drawLine(x2,y2,x0,y0,color);
}

/*****************************************************************************
 * @name       :void Fill_Triangle(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
 * @date       :2020 02 05
 * @function   :filling a triangle at a specified position
 * @parameters :x0:the beginning x coordinate of the triangular edge 
                y0:the beginning y coordinate of the triangular edge 
				x1:the vertex x coordinate of the triangular
				y1:the vertex y coordinate of the triangular
				x2:the ending x coordinate of the triangular edge 
				y2:the ending y coordinate of the triangular edge 
 * @retvalue   :None
******************************************************************************/ 
void classGraphics::drawFillTriangle(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2, uint16_t color)
{
	uint16_t a, b, y, last;
	int dx01, dy01, dx02, dy02, dx12, dy12;
	long sa = 0;
	long sb = 0;
 	if (y0 > y1) 
	{
        _swap(&y0,&y1); 
		_swap(&x0,&x1);
 	}
 	if (y1 > y2) 
	{
        _swap(&y2,&y1); 
		_swap(&x2,&x1);
 	}
  if (y0 > y1) 
	{
        _swap(&y0,&y1); 
		_swap(&x0,&x1);
    }
	if(y0 == y2) 
	{ 
		a = b = x0;
		if(x1 < a)
    {
			a = x1;
    }
    else if(x1 > b)
    {
			b = x1;
    }
    if(x2 < a)
    {
			a = x2;
    }
		else if(x2 > b)
    {
			b = x2;
    }
		_fill(a,y0,b,y0,color);
        return;
	}
	dx01 = x1 - x0;
	dy01 = y1 - y0;
	dx02 = x2 - x0;
	dy02 = y2 - y0;
	dx12 = x2 - x1;
	dy12 = y2 - y1;
	
	if(y1 == y2)
	{
		last = y1; 
	}
  else
	{
		last = y1-1; 
	}
	for(y=y0; y<=last; y++) 
	{
		a = x0 + sa / dy01;
		b = x0 + sb / dy02;
		sa += dx01;
    sb += dx02;
    if(a > b)
    {
			_swap(&a,&b);
	}
	_fill(a,y,b,y,color);
	}
	sa = dx12 * (y - y1);
	sb = dx02 * (y - y0);
	for(; y<=y2; y++) 
	{
		a = x1 + sa / dy12;
		b = x0 + sb / dy02;
		sa += dx12;
		sb += dx02;
		if(a > b)
		{
			_swap(&a,&b);
		}
		_fill(a,y,b,y,color);
	}
}

/*****************************************************************************
 * @name       :void DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
 * @date       :2020 02 05
 * @function   :Draw a rectangle
 * @parameters :x1:the beginning x coordinate of the rectangle
                y1:the beginning y coordinate of the rectangle
				x2:the ending x coordinate of the rectangle
				y2:the ending y coordinate of the rectangle
 * @retvalue   :None
******************************************************************************/
void classGraphics::drawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
	drawLine(x1,y1,x2,y1,color);
	drawLine(x1,y1,x1,y2,color);
	drawLine(x1,y2,x2,y2,color);
	drawLine(x2,y1,x2,y2,color);
} 

/*****************************************************************************
 * @name       :void DrawFillRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
 * @date       :2020 02 05
 * @function   :Filled a rectangle
 * @parameters :x1:the beginning x coordinate of the filled rectangle
                y1:the beginning y coordinate of the filled rectangle
				x2:the ending x coordinate of the filled rectangle
			    y2:the ending y coordinate of the filled rectangle
 * @retvalue   :None
******************************************************************************/  
void classGraphics::drawFillRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
	_fill(x1,y1,x2,y2,color);
} 

/*****************************************************************************
 * @name       :void _draw_circle_8(int xc, int yc, int x, int y, uint16_t c)
 * @date       :2018-08-09 
 * @function   :8 symmetry circle drawing algorithm (internal call)
 * @parameters :xc:the x coordinate of the Circular center 
                yc:the y coordinate of the Circular center 
				x:the x coordinate relative to the Circular center 
				y:the y coordinate relative to the Circular center 
				c:the color value of the circle
 * @retvalue   :None
******************************************************************************/  
void classGraphics::_draw_circle_8(int xc, int yc, int x, int y, uint16_t c)
{
	drawPoint(xc + x, yc + y, c);
	drawPoint(xc - x, yc + y, c);
	drawPoint(xc + x, yc - y, c);
	drawPoint(xc - x, yc - y, c);
	drawPoint(xc + y, yc + x, c);
	drawPoint(xc - y, yc + x, c);
	drawPoint(xc + y, yc - x, c);
	drawPoint(xc - y, yc - x, c);
}

/*****************************************************************************
 * @name       :void Draw_Circle(int xc, int yc,uint16_t c,int r, int fill)
 * @date       :2020 02 05
 * @function   :Draw a circle of specified size at a specified location
 * @parameters :xc:the x coordinate of the Circular center 
                yc:the y coordinate of the Circular center 
				r:Circular radius
				fill:1-filling,0-no filling
 * @retvalue   :None
******************************************************************************/  
void classGraphics::drawCircle(int xc, int yc,uint16_t c,int r, int fill)
{
	int x = 0, y = r, yi, d;
	d = 3 - 2 * r;
	if (fill) 
	{
		while (x <= y) {
			for (yi = x; yi <= y; yi++)
				_draw_circle_8(xc, yc, x, yi, c);

			if (d < 0) {
				d = d + 4 * x + 6;
			} else {
				d = d + 4 * (x - y) + 10;
				y--;
			}
			x++;
		}
	} else 
	{
		while (x <= y) {
			_draw_circle_8(xc, yc, x, y, c);
			if (d < 0) {
				d = d + 4 * x + 6;
			} else {
				d = d + 4 * (x - y) + 10;
				y--;
			}
			x++;
		}
	}
}

/*******************************************************
* Set Font
*
********************************************************/
void classGraphics::setFont(FONTYPE fontype)
{
	switch(fontype)
	{
		case font8x12:
		cfont.font =(unsigned char*) SmallFont;
		cfont.x_size=SmallFont[0];
		cfont.y_size=SmallFont[1];
		cfont.offset=SmallFont[2];
		cfont.numchars=SmallFont[3];
		break;
		case font16x16:
		cfont.font =(unsigned char*) BigFont;
		cfont.x_size=BigFont[0];
		cfont.y_size=BigFont[1];
		cfont.offset=BigFont[2];
		cfont.numchars=BigFont[3];
		break;
		case font7seg:
		cfont.font = (unsigned char*) SevenSegNumFont;
		cfont.x_size=SevenSegNumFont[0];
		cfont.y_size=SevenSegNumFont[1];
		cfont.offset=SevenSegNumFont[2];
		cfont.numchars=SevenSegNumFont[3];
		break;
		case font48:
		cfont.font = (unsigned char*) GroteskBold24x48;
		cfont.x_size=GroteskBold24x48[0];
		cfont.y_size=GroteskBold24x48[1];
		cfont.offset=GroteskBold24x48[2];
		cfont.numchars=GroteskBold24x48[3];
		break;
		case font7_96_144:
		cfont.font = (unsigned char*) SevenSegment96x144Num;
		cfont.x_size=SevenSegment96x144Num[0];
		cfont.y_size=SevenSegment96x144Num[1];
		cfont.offset=SevenSegment96x144Num[2];
		cfont.numchars=SevenSegment96x144Num[3];
		break;
		default:
		break;
		
	}
	
}

/*****************************************************************************
 * @name       :void ShowChar(uint16_t x,uint16_t y,uint16_t fc, uint16_t bc, uint8_t num,uint8_t size,uint8_t mode)
 * @date       :2020 02 05
 * @function   :Display a single English character
 * @parameters :x:the begining x coordinate of the Character display position
                y:the begining y coordinate of the Character display position
				fc:the color value of display character
				bc:the background color of display character
				num:the ascii code of display character(0~94)
				size:the size of display character
				mode:0-no overlying,1-overlying
 * @retvalue   :None
******************************************************************************/ 
void classGraphics::showChar(uint16_t x,uint16_t y,uint16_t fc, uint16_t bc, uint8_t num,uint8_t Size,uint8_t mode)
{  
    uint8_t temp;
    uint8_t pos,t;
	uint16_t colortemp=Display.POINT_COLOR;      
		   
	num=num-' ';
	Display.Tft_SetWindows(x,y,x+Size/2-1,y+Size-1);
	if(!mode) 
	{
		
		for(pos=0;pos<Size;pos++)
		{
			if(Size==12)temp=asc2_1206[num][pos];
			else temp=asc2_1608[num][pos];		 
			for(t=0;t<Size/2;t++)
		    {                 
		        if(temp&0x01)Display.Tft_WR_DATA_16Bit(fc); 
				else Display.Tft_WR_DATA_16Bit(bc); 
				temp>>=1; 
				
		    }
			
		}	
	}else
	{
		for(pos=0;pos<Size;pos++)
		{
			if(Size==12)temp=asc2_1206[num][pos];
			else temp=asc2_1608[num][pos];		 
			for(t=0;t<Size/2;t++)
		    {   
				Display.POINT_COLOR=fc;              
		        if(temp&0x01)drawPoint(x+t,y+pos,Display.POINT_COLOR);  
		        temp>>=1; 
		    }
		}
	}
	Display.POINT_COLOR=colortemp;	
	Display.Tft_SetWindows(0,0,Display.lcddev.width-1,Display.lcddev.height-1);  	   	 	  
}

/*****************************************************************************
 * @name       :void Show_Str(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *str,uint8_t size,uint8_t mode)
 * @date       :2018-08-09 
 * @function   :Display Chinese and English strings
 * @parameters :x:the begining x coordinate of the Chinese and English strings
                y:the begining y coordinate of the Chinese and English strings
				fc:the color value of Chinese and English strings
				bc:the background color of Chinese and English strings
				str:the start address of the Chinese and English strings
				size:the size of Chinese and English strings
				mode:0-no overlying,1-overlying
 * @retvalue   :None
******************************************************************************/	   		   
void classGraphics::showStr(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *str,uint8_t Size,uint8_t mode)
{					
	uint16_t x0=x;							  	  
  	uint8_t bHz=0;     
    while(*str!=0)
    { 
        if(!bHz)
        {
			if(x>(Display.lcddev.width-Size/2)||y>(Display.lcddev.height-Size)) 
			return; 
	        if(*str>0x80)bHz=1;
	        else              
	        {          
		        if(*str==0x0D)
		        {         
		            y+=Size;
					x=x0;
		            str++; 
		        }  
		        else
				{
					if(Size>16)
					{  
					  showChar(x,y,fc,bc,*str,16,mode);
					  x+=8; 
					}
					else
					{
					  showChar(x,y,fc,bc,*str,Size,mode);
					  x+=Size/2; 
					}
				} 
				str++; 
		        
	        }
        }else
        {   
			if(x>(Display.lcddev.width-Size)||y>(Display.lcddev.height-Size)) 
			return;  
            bHz=0;   
	        str+=2; 
	        x+=Size;	    
        }						 
    }   
}

/*****************************************************************************
 * @name       :void ShowString(uint16_t x,uint16_t y,uint8_t size,uint8_t *p,uint8_t mode)
 * @date       :2020 02 05
 * @function   :Display English string
 * @parameters :x:the beginning x coordinate of the English string
                y:the beginning y coordinate of the English string
				p:the start address of the English string
			    size:the size of display character
				mode:0-no overlying,1-overlying
 * @retvalue   :None
******************************************************************************/   	  
void classGraphics::showString(uint16_t x,uint16_t y,uint8_t Size,uint8_t *p,uint8_t mode)
{         
    while((*p<='~')&&(*p>=' '))
    {   
		if(x>(Display.lcddev.width-1)||y>(Display.lcddev.height-1)) 
		return;     
        showChar(x,y,Display.POINT_COLOR,Display.BACK_COLOR,*p,Size,mode);
        x+=Size/2;
        p++;
    }  
} 

/*****************************************************************************
 * @name       :void StrCenter(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *str,uint8_t size,uint8_t mode)
 * @date       :2020 02 05
 * @function   :Centered display of English and Chinese strings
 * @parameters :x:the beginning x coordinate of the Chinese and English strings
                y:the beginning y coordinate of the Chinese and English strings
				fc:the color value of Chinese and English strings
				bc:the background color of Chinese and English strings
				str:the start address of the Chinese and English strings
				size:the size of Chinese and English strings
				mode:0-no overlying,1-overlying
 * @retvalue   :None
******************************************************************************/ 
void classGraphics::strCenter(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *str,uint8_t Size,uint8_t mode)

{
	uint16_t len=strlen((const char *)str);
	uint16_t x1=(Display.lcddev.width-len*8)/2;
	showStr(x+x1,y,fc,bc,str,Size,mode);
} 

/*****************************************************************************
 * @name       :void ShowNum(uint16_t x,uint16_t y,u32 num,uint8_t len,uint8_t size)
 * @date       :2020 02 05
 * @function   :Display number
 * @parameters :x:the beginning x coordinate of the number
                y:the beginning y coordinate of the number
				num:the number(0~4294967295)
				len:the length of the display number
				size:the size of display number
 * @retvalue   :None
******************************************************************************/  			 
void classGraphics::showNum(uint16_t x,uint16_t y,uint32_t num,uint8_t len,uint8_t Size)
{         	
	uint8_t t,temp;
	uint8_t enshow=0;	
	for(t=0;t<len;t++)
	{
		temp=(num/mypow(10,len-t-1))%10;
		if(enshow==0&&t<(len-1))
		{
			if(temp==0)
			{
				showChar(x+(Size/2)*t,y,Display.POINT_COLOR,Display.BACK_COLOR,' ',Size,0);
				continue;
			}else enshow=1; 
		 	 
		}
	 	showChar(x+(Size/2)*t,y,Display.POINT_COLOR,Display.BACK_COLOR,temp+'0',Size,0); 
	}
} 

/**********************************************************************************
* Print char using selected font by SetFont() Function
*
*
**********************************************************************************/
void classGraphics::printChar(uint8_t c, int x, int y,uint16_t fc, uint16_t bc)
{
	uint8_t i,ch;
	uint16_t j;
	uint16_t temp;
	
	if (!_transparent)
	{
		if (1)//orient==PORTRAIT
		{
			Display.Tft_SetWindows(x,y,x+cfont.x_size-1,y+cfont.y_size-1);
			temp=((c-cfont.offset)*((cfont.x_size/8)*cfont.y_size))+4;
			for(j=0;j<((cfont.x_size/8)*cfont.y_size);j++)
			{
				ch=cfont.font[temp];//&cfont.font[temp]
				for(i=0;i<8;i++)
				{
					if((ch&(1<<(7-i)))!=0)
					{
						Display.Tft_WR_DATA_16Bit(fc);
					}
					else
					{
						Display.Tft_WR_DATA_16Bit(bc);
					}
				}
				temp++;
			}
		}
		else
		{
			temp=((c-cfont.offset)*((cfont.x_size/8)*cfont.y_size))+4;

			for(j=0;j<((cfont.x_size/8)*cfont.y_size);j+=(cfont.x_size/8))
			{
				Display.Tft_SetWindows(x,x+cfont.x_size-1,y+(j/(cfont.x_size/8)),y+(j/(cfont.x_size/8)));
				for (int zz=(cfont.x_size/8)-1; zz>=0; zz--)
				{
					ch=cfont.font[temp+zz];//&cfont.font[temp+zz]
					for(i=0;i<8;i++)
					{
						if((ch&(1<<i))!=0)
						{
							Display.Tft_WR_DATA_16Bit(fc);
						}
						else
						{
							Display.Tft_WR_DATA_16Bit(bc);
						}
					}
				}
				temp+=(cfont.x_size/8);
			}
		}
	}
	else
	{
		temp=((c-cfont.offset)*((cfont.x_size/8)*cfont.y_size))+4;
		for(j=0;j<cfont.y_size;j++)
		{
			for (int zz=0; zz<(cfont.x_size/8); zz++)
			{
				ch=cfont.font[temp+zz];
				for(i=0;i<8;i++)
				{
					Display.Tft_SetWindows(x+i+(zz*8),y+j,x+i+(zz*8)+1,y+j+1);
					
					if((ch&(1<<(7-i)))!=0)
					{
						Display.Tft_WR_DATA_16Bit(fc);
					}
				}
			}
			temp+=(cfont.x_size/8);
		}
	}

}

/**********************************************************************************
* Rotate char using selected font by SetFont() Function
*
*
**********************************************************************************/

void classGraphics::rotateChar(uint8_t c, int x, int y, int pos, int deg, uint16_t fc, uint16_t bc)
{
	uint8_t i,j,ch;
	uint16_t temp;
	int newx,newy;
	double radian;
	radian=deg*0.0175;


	temp=((c-cfont.offset)*((cfont.x_size/8)*cfont.y_size))+4;
	for(j=0;j<cfont.y_size;j++)
	{
		for (int zz=0; zz<(cfont.x_size/8); zz++)
		{
			ch=cfont.font[temp+zz];
			for(i=0;i<8;i++)
			{
				newx=x+(((i+(zz*8)+(pos*cfont.x_size))*cos(radian))-((j)*sin(radian)));
				newy=y+(((j)*cos(radian))+((i+(zz*8)+(pos*cfont.x_size))*sin(radian)));

				Display.Tft_SetWindows(newx,newy,newx+1,newy+1);
				
				if((ch&(1<<(7-i)))!=0)
				{
					Display.Tft_WR_DATA_16Bit(fc);
				}
				else
				{
					if (!_transparent)
					Display.Tft_WR_DATA_16Bit(bc);
				}
			}
		}
		temp+=(cfont.x_size/8);
	}
}

/**********************************************************************************
* Print string using selected font by SetFont() Function
*
*
**********************************************************************************/
void classGraphics::print(char *st, int x, int y, int deg, uint16_t fc, uint16_t bc)
{
	int stl, i;
	stl = strlen(st);
	if (orient==PORTRAIT)
	{
		if (x==RIGHT)
		x=(LCD_W+1)-(stl*cfont.x_size);
		if (x==CENTER)
		x=((LCD_W+1)-(stl*cfont.x_size))/2;
	}
	else
	{
		if (x==RIGHT)
		x=(LCD_H+1)-(stl*cfont.x_size);
		if (x==CENTER)
		x=((LCD_H+1)-(stl*cfont.x_size))/2;
	}

	for (i=0; i<stl; i++)
	if (deg==0)
	printChar(*st++, x + (i*(cfont.x_size)), y, fc, bc);
	else
	rotateChar(*st++, x, y, i, deg, fc, bc);
}

/*****************************************************************************
 * @name       :void Drawbmp16(uint16_t x,uint16_t y,uint16_t w,uint16_t h,const unsigned char *p)
 * @date       :2020 02 05
 * @function   :Display a 16-bit BMP image
 * @parameters :x:the beginning x coordinate of the BMP image
                y:the beginning y coordinate of the BMP image
				p:the start address of image array
 * @retvalue   :None
******************************************************************************/ 
void classGraphics::drawBmp16(uint16_t x,uint16_t y,uint16_t w,uint16_t h,const unsigned char *p) 
{
  	int i; 
	unsigned char picH,picL; 
	Display.Tft_SetWindows(x,y,x+w-1,y+h-1);
    for(i=0;i<w*h;i++)
	{	
	 	picL=*(p+i*2);	
		picH=*(p+i*2+1);				
		Display.Tft_WR_DATA_16Bit(picH<<8|picL);
	}	
	Display.Tft_SetWindows(0,0,Display.lcddev.width-1,Display.lcddev.height-1);	

}


/*************************************************************************
*  Representa un bitmap almacenado en la flash externa 25Q128
*  x coordenada izquierda del bitmap
*  y coordenada superior del bitmap
*  sx ancho del bitmap
*  sy alto del bitmap
*  p apunta al inicio de datos den la flash externa W25Q128
*************************************************************************/
void classGraphics::drawBitmap_from_w25q(int x, int y, int sx, int sy,uint32_t p, int scale)
{
	unsigned int col;
	int tx, ty, tc, tsx, tsy;
	uint16_t word_counter = 0;
	uint32_t page = 0;
	uint16_t * pointer;
	if (scale==1)
	{
		W25q.IO_Read_nBytes(p,512);
	    pointer = &W25q.u.temp16_buffer[0];
		for (ty=sy-1; ty>=0; ty--) //for (ty=0; ty<sy; ty++) espejo vertical
		{
			Display.Tft_SetWindows(x,y+ty,x+sx, y+sy);
			//for (tx=sx-1; tx>=0; tx--)//espejo for (tx=0; tx<sx; tx++)
			for (tx=0; tx<sx; tx++)
			{
				
				col=*pointer++;
				Display.Tft_WR_DATA_16Bit(col);
				word_counter++;
				if(word_counter>=256)
				{
					word_counter=0;
					page++;
					W25q.IO_Read_nBytes(p+page*512UL,512);
					pointer = &W25q.u.temp16_buffer[0];
				}
				
			}

		}
	}
	else
	{
		W25q.IO_Read_nBytes(p,512);
		pointer = &W25q.u.temp16_buffer[0];
		for (ty=0; ty<sy; ty++)
		{
			for (tsy=0; tsy<scale; tsy++)
			{
				Display.Tft_SetWindows(x, y+(ty*scale)+tsy, x+((sx*scale)-1), y+(ty*scale)+tsy);
				for (tx=0; tx<sx; tx++)
				{
				   col=*pointer++;
				   Display.Tft_WR_DATA_16Bit(col);
				   word_counter++;
				   if(word_counter>=256)
				   {
					  word_counter=0;
					  page++;
					  W25q.IO_Read_nBytes(p+page*512,512);
					  pointer = &W25q.u.temp16_buffer[0];
				   }
				}
			}
		}
	}
}

/************************************************************************
*  Representa un bitmap almacenado en un array de 8 bits
*  x coordenada izquierda del bitmap
*  y coordenada superior del bitmap
*  sx ancho del bitmap
*  sy alto del bitmap
*p apunta al inicio de datos den la flash externa
*************************************************************************/
void classGraphics::drawBitmap(int x, int y, int sx, int sy,uint32_t * p, int scale)
{
	unsigned int col;
	int tx, ty, tc, tsx, tsy;
	if (scale==1)
	{
		for (ty=sy-1; ty>=0; ty--) //for (ty=0; ty<sy; ty++) espejo vertical
		{
			Display.Tft_SetWindows(x, y+ty, x+sx, y+sy);
			//for (tx=sx-1; tx>=0; tx--)//espejo for (tx=0; tx<sx; tx++)
			
			for (tx=0; tx<sx;)
			{
				//col=((uint16_t)*(p+1)<<8) |*p;
				col=(uint16_t) *p & 0xffff;
				Display.Tft_WR_DATA_16Bit(col);
				tx++;
				col=(uint16_t) (*p >> 16) & 0xffff;
				Display.Tft_WR_DATA_16Bit(col);
				tx++;
				
				p +=1;
				
			}
			
		}
	}
	else
	{
		for (ty=0; ty<sy;)
		{
			for (tsy=0; tsy<scale; tsy++)
			{
				Display.Tft_SetWindows(x,y+(ty*scale)+tsy, x+((sx*scale)-1), y+(ty*scale)+tsy);
				for (tx=0; tx<sx; tx++)
				{
					col=(uint16_t) *p & 0xffff;
					Display.Tft_WR_DATA_16Bit(col);
					tx++;
					col=(uint16_t) (*p >> 16) & 0xffff;
					Display.Tft_WR_DATA_16Bit(col);
					tx++;
					p +=1;
				}
			}
		}
	}
}

/**********************************************************************************
* Print Integer number using selected font by SetFont() Function
*
*
**********************************************************************************/
void classGraphics::printNumI(long num, int x, int y, int length, char filler, uint16_t fc, uint16_t bc)
{
	char buf[25];
	char st[27];
	bool neg=false;
	int c=0, f=0;
	
	if (num==0)
	{
		if (length!=0)
		{
			for (c=0; c<(length-1); c++)
			st[c]=filler;
			st[c]=48;
			st[c+1]=0;
		}
		else
		{
			st[0]=48;
			st[1]=0;
		}
	}
	else
	{
		if (num<0)
		{
			neg=true;
			num=-num;
		}
		
		while (num>0)
		{
			buf[c]=48+(num % 10);
			c++;
			num=(num-(num % 10))/10;
		}
		buf[c]=0;
		
		if (neg)
		{
			st[0]=45;
		}
		
		if (length>(c+neg))
		{
			for (int i=0; i<(length-c-neg); i++)
			{
				st[i+neg]=filler;
				f++;
			}
		}

		for (int i=0; i<c; i++)
		{
			st[i+neg+f]=buf[c-i-1];
		}
		st[c+neg+f]=0;
	}

	print(st,x,y,0,fc,bc);
}

/**********************************************************************************
* Print Float number using selected font by SetFont() Function
*
*
**********************************************************************************/
void classGraphics::printNumF(double num, uint8_t lenght, uint8_t dec, char filler, int x, int y, uint16_t fc, uint16_t bc)
{
	char st[27];
	char buffer[27];
	bool neg=false;
	int8_t offset;
	if (dec<1)
	dec=1;
	else if (dec>5)
	dec=5;

	if (num<0)
	neg = true;
	sprintf(st, "%*.*f",lenght,dec, num);
	if((num < 10) & (lenght == 2))
	offset = 1;
	if((num < 100) & (lenght == 3))
	offset = 1;
	for(int i=0;i<27;i++)
	buffer[i+offset] = st[i];
	for(int i=0;i<offset;i++)
	buffer[i] = filler;
	print(buffer,x,y,0,fc,bc);
}

/************************************************************
* Test Page
************************************************************/
void classGraphics::drawTestPage(uint8_t *str)
{
	Display.Tft_Clear(WHITE);
	_fill(0,0,Display.lcddev.width-1,20,BLUE);
	_fill(0,Display.lcddev.height-20,Display.lcddev.width-1,Display.lcddev.height-1,BLUE);
	Display.POINT_COLOR=WHITE;
	strCenter(0,2,WHITE,BLUE,str,16,1);//????
	strCenter(0,Display.lcddev.height-18,WHITE,BLUE,(uint8_t*)("http://www.ledoelectronics.com"),16,1);
}











