/****************************************************************************
	Knihovna funkci pro kresleni grafickych prvku na displej. Podporovany 
	jsou tvary jako cara, obdelnik, kruh, elipsa, zkosene a zaoblene obdelniky.

	Dale je mozne kreslit bitmapy v preddefinovanem formatu. Je implementovana 
	podpora pruhlednosti.

*****************************************************************************/
#include "stdafx.h"
#include "GLCD.h"
#include <math.h>

/********************************************************************
Vykreslí čáru z pozice (x1, y1) do (x2, y2). Problémy spojené s kreslením
jsou popsány v textu bakalářské práce.

Vstupy:
	int x1					Pozice x1
	int y1					Pozice y1
	int x2					Pozice x2
	int y2					Pozice y2

Výstup:
	void
*********************************************************************/

void LCD_line(int x1,int y1,int x2, int y2, RGB_COLORS color)
{
	int k,q;
	int i;
	int X1=0,X2=0,Y1=0,Y2=0;
	X1 = x2>x1?x1:x2;						//Přeházení souřadnic tak, aby se kreslilo zleva doprava
	Y1 = x2>x1?y1:y2;
	X2 = x2>x1?x2:x1;
	Y2 = x2>x1?y2:y1;
	if (x2 == x1){							//Pokud kreslíme svislou čáru
		
		for (i = (Y1>Y2?Y2:Y1);i<=(Y1>Y2?Y1:Y2);i++){
			LCD_put_pix(X2,i,color);		//nic nepočítáme
		}


	}else if ((X2-X1)>((Y2-Y1)>0?(Y2-Y1):-(Y2-Y1)))
		{									//Pokud je čára "spíše naležato""
		LCD_put_pix(x1,y1,color);			//Počáteční a koncový bod
		LCD_put_pix(x2,y2,color);
		k = ((100*(Y2-Y1))/(X2-X1));		//Výpočet podle y = kx+q
		q = Y1-k*X1/100;
		for (i = X1+1;i<X2;i++){
			LCD_put_pix(i,i*k/100+q,color);
		}
		
	}
	else
	{										//Pokud je čára "spíše svislá"
		X1 = y2>y1?x1:x2;
		Y1 = y2>y1?y1:y2;
		X2 = y2>y1?x2:x1;
		Y2 = y2>y1?y2:y1;
		LCD_put_pix(x1,y1,color);			//Kreslení krajních bodů
		LCD_put_pix(x2,y2,color);
		k = ((100*(X2-X1))/(Y2-Y1));		//Výpočet dle x = ky+q
		q = X1-k*Y1/100;
		for (i = Y1;i<Y2;i++){
			LCD_put_pix(i*k/100+q,i,color);
		}
		
	}
}

/****************************************************************************
	Zatmavi caru (puvodni prani bylo vytvoreni stinu)

	Vstup: 
		x1, y1:		bod A
		x2, y2:		bod B

	Výstup:
		není

*****************************************************************************/
void LCD_darken_line(int x1,int y1,int x2, int y2)
{
	int k,q;
	int i;
	int X1=0,X2=0,Y1=0,Y2=0;
	X1 = x2>x1?x1:x2;						//Přeházení souřadnic tak, aby se kreslilo zleva doprava
	Y1 = x2>x1?y1:y2;
	X2 = x2>x1?x2:x1;
	Y2 = x2>x1?y2:y1;
	if (x2 == x1){							//Pokud kreslíme svislou čáru
		
		for (i = (Y1>Y2?Y2:Y1);i<=(Y1>Y2?Y1:Y2);i++){
			LCD_darken_pix(X2,i);			//nic nepočítáme
		}


	}else if ((X2-X1)>((Y2-Y1)>0?(Y2-Y1):-(Y2-Y1)))
		{									//Pokud je čára "spíše naležato""
		LCD_darken_pix(x1,y1);				//Počáteční a koncový bod
		LCD_darken_pix(x2,y2);
		k = ((100*(Y2-Y1))/(X2-X1));		//Výpočet podle y = kx+q
		q = Y1-k*X1/100;
		for (i = X1+1;i<X2;i++){
			LCD_darken_pix(i,i*k/100+q);
		}
		
	}
	else
	{										//Pokud je čára "spíše svislá"
		X1 = y2>y1?x1:x2;
		Y1 = y2>y1?y1:y2;
		X2 = y2>y1?x2:x1;
		Y2 = y2>y1?y2:y1;
		LCD_darken_pix(x1,y1);				//Kreslení krajních bodů
		LCD_darken_pix(x2,y2);
		k = ((100*(X2-X1))/(Y2-Y1));		//Výpočet dle x = ky+q
		q = X1-k*Y1/100;
		for (i = Y1;i<Y2;i++){
			LCD_darken_pix(i*k/100+q,i);
		}
		
	}
}

/********************************************************************
Vykreslí obdélník, zadáme-li horní levý a dolní pravý bod. Lze zvolit
tloušťku čáry.

Vstupy:
	int xA					Pozice x horního levého bodu
	int yA					Pozice y horního levého bodu
	int xC					Pozice x dolního pravého bodu
	int yC					Pozice y dolního pravého bodu
	int width				Tloušťka čáry
	color:					Barva

Výstup:
	void
*********************************************************************/

void LCD_rect(TRect *R,int width, RGB_COLORS color)
{	int used_width,i;
	if (width <=0) return;
	used_width = ((R->xC-R->xA)>>1)<(width)?((R->xC-R->xA)>>1):width;	//Pokud je tloušťka čáry větší než šířka obdélníka, oprav ji
	for (i = 0;i<used_width;i++)
	{
		LCD_line(R->xA+i,R->yA,R->xA+i,R->yC,color);							//Vykresli příslušný počet svislých čar	
		LCD_line(R->xC-i,R->yA,R->xC-i,R->yC,color);
	}

	used_width = ((R->yC-R->yA)>>1)<(width)?((R->yC-R->yA)>>1):width;	//Pokud je tloušťka čáry větší než výška obdélníka, oprav ji

	for (i = 0;i<used_width;i++)
	{
		LCD_line(R->xA,R->yA+i,R->xC,R->yA+i,color);							//Opět vykresli příslušný počet čar
		LCD_line(R->xA,R->yC-i,R->xC,R->yC-i,color);
	}
return;
}

/****************************************************************************
	Vystinuje obdelnik o dane sirce cary

	Vstup: 
		R:			Ukazatel na obdelnik
		width:		Sirka cary

	Výstup:
		není

*****************************************************************************/
void LCD_darken_rect(TRect *R,int width)
{	int used_width,i;
	if (width <=0) return;
	used_width = ((R->xC-R->xA)>>1)<(width)?((R->xC-R->xA)>>1):width;			//Pokud je tloušťka čáry větší než šířka obdélníka, oprav ji
	for (i = 0;i<used_width;i++)
	{
		LCD_darken_line(R->xA+i,R->yA,R->xA+i,R->yC);							//Vykresli příslušný počet svislých čar	
		LCD_darken_line(R->xC-i,R->yA,R->xC-i,R->yC);
	}

	used_width = ((R->yC-R->yA)>>1)<(width)?((R->yC-R->yA)>>1):width;			//Pokud je tloušťka čáry větší než výška obdélníka, oprav ji

	for (i = 0;i<used_width;i++)
	{
		LCD_darken_line(R->xA,R->yA+i,R->xC,R->yA+i);							//Opět vykresli příslušný počet čar
		LCD_darken_line(R->xA,R->yC-i,R->xC,R->yC-i);
	}
return;
}

/****************************************************************************
	Vykresleni kruhu

	Vstup: 
		C:			Ukazatel na kruh
		color:		Barva kruhu

	Výstup:
		není

*****************************************************************************/
void LCD_circ(TCircle *C, RGB_COLORS color)
{
	double i = 0;
	for (i = 0; i < 6.28; i+=0.01)
	{
		LCD_put_pix((int)(C->x+C->r*cos(i)),(int)(C->y+C->r*sin(i)),color);
	}
}


/****************************************************************************
	Vykresleni elipsy

	Vstup: 
		R:			Obdelnik, ktery lze opsat elipse
		color:		Barva

	Výstup:
		není

*****************************************************************************/
void LCD_elipse(TRect *R, RGB_COLORS color)
{
	double i = 0;
	TElipse E = {(R->xC+R->xA)/2,(R->yC+R->yA)/2,(R->xC-R->xA)/2,(R->yC-R->yA)/2};
	for (i = 0; i < 6.28; i+=0.01)
	{
		LCD_put_pix((int)(E.x+E.a*cos(i)),(int)(E.y+E.b*sin(i)),color);
	}
}


/****************************************************************************
	Vykresli vyplnenou elipsu

	Vstup: 
		R:			Obdelnik opsany elipse
		color:		barva obdelniku

	Výstup:
		není

*****************************************************************************/
void LCD_felipse(TRect *R, RGB_COLORS color)
{
	double i = 0;
	int x = 0,yu = 0, yd = 0;
	TElipse E = {(R->xC+R->xA)/2,(R->yC+R->yA)/2,(R->xC-R->xA)/2,(R->yC-R->yA)/2};
	for (i = 0; i < 3.14; i+=0.01)						//Z definicniho vztahu elipsy
	{
		x = (int)(E.x+E.a*cos(i));						//Kreslime obe poloviny naraz
		yd =(int)(E.y+E.b*sin(i));
		yu =(int)(E.y+E.b*sin(-i));
		LCD_line(x,yu,x,yd,color);
	}
}


/****************************************************************************
	Vykresli vyplneny obdelnik

	Vstup: 
		R:				obdelnik
		color:			barva

	Výstup:
		není

*****************************************************************************/
void LCD_frect(TRect *R,RGB_COLORS color)				
{
	int u = 0;
	for (u = R->yA; u <= R->yC; u++)
		LCD_line(R->xA,u,R->xC,u,color);
}


/****************************************************************************
	Vykresli zaobleny vyplneny obdelnik - metoda je sice hezka, ale nepouziva se.

	Je sice soucasti knihovny, kompilator ji ale preskakuje.

	Vstup: 
		R:			obdelnik
		color:		barva
		r:			polomer zaobleni

	Výstup:
		není

*****************************************************************************/
void LCD_frrect(TRect *R,RGB_COLORS color,unsigned char r)
{
	double i = 0;
	int x = 0,yu = 0, yd = 0;
	TRect R1 = {R->xA,R->yA+r,R->xC,R->yC-r};		
	TRect R2 = {R->xA+r,R->yA,R->xC-r,R->yC};
	TElipse E = {R->xA+r,R->yA+r,r,r};
	LCD_frect(&R1,color);							//Nejprve vykreslime kriz bez zaoblenych rohu (proste pravouhlou cast)
	LCD_frect(&R2,color);
	for (i = 1.57; i < 3.14; i+=0.001)				//Potom kazdy ze zaoblenych rohu
	{
		x = (int)(E.x+E.a*cos(i));
		yd =(int)E.y;
		yu =(int)(E.y+E.b*sin(-i));
		LCD_line(x,yu,x,yd,color);
	}
	E.y = R->yC-r;
	for (i = 1.57; i < 3.14; i+=0.001)
	{
		x = (int)(E.x+E.a*cos(i));
		yd =(int)(E.y+E.b*sin(i));
		yu =(int)E.y;
		LCD_line(x,yu,x,yd,color);
	}

	E.x = R->xC-r;
	for (i = 0; i < 1.57; i+=0.001)
	{
		x = (int)(E.x+E.a*cos(i));
		yd =(int)(E.y+E.b*sin(i));
		yu =(int)E.y;
		LCD_line(x,yu,x,yd,color);
	}
	E.y = R->yA+r;
	for (i = 0; i < 1.57; i+=0.001)
	{
		x = (int)(E.x+E.a*cos(i));
		yd =(int)E.y;
		yu =(int)(E.y+E.b*sin(-i));
		LCD_line(x,yu,x,yd,color);
	}
}

/****************************************************************************
	Vykresli zkoseny obdelnik - vyplneny

	Vstup: 
		R:			obdelnik
		color:		barva
		r:			zkoseni

	Výstup:
		není

*****************************************************************************/
void LCD_fcrect(TRect *R,RGB_COLORS color,unsigned char r)
{
	TRect R1 = {R->xA,R->yA+r,R->xC,R->yC-r};
	LCD_frect(&R1,color);
	for (char i = 0; i < r; i++)
	{
		LCD_line(R->xA+r-i, R->yA+i,R->xC-r+i, R->yA+i, color);
	}

	for (char i = 0; i < r; i++)
	{
		LCD_line(R->xA+r-i, R->yC-i,R->xC-r+i, R->yC-i, color);
	}
}


/****************************************************************************
	Vykresli zkoseny obdelnik - prazdny

	Vstup: 
		R:			obdelnik
		color:		barva
		r:			zkoseni

	Výstup:
		není

*****************************************************************************/
void LCD_crect(TRect *R,RGB_COLORS color,unsigned char r)
{


	LCD_line(R->xA+r,R->yA,R->xC-r, R->yA,color);
	LCD_line(R->xA+r,R->yC,R->xC-r, R->yC,color);
	LCD_line(R->xA,R->yA+r,R->xA, R->yC-r,color);
	LCD_line(R->xC,R->yA+r,R->xC, R->yC-r,color);
	LCD_line(R->xA,R->yA+r,R->xA+r, R->yA,color);
	LCD_line(R->xA,R->yC-r,R->xA+r, R->yC,color);
	LCD_line(R->xC-r,R->yA,R->xC, R->yA+r,color);
	LCD_line(R->xC-r,R->yC,R->xC, R->yC-r,color);
}


/****************************************************************************
	Vykresli zaobleny obdelnik

	Vstup: 
		R:		obdelnik
		color:	barva
		r:		polomer

	Výstup:
		není

*****************************************************************************/
void LCD_rrect(TRect *R,RGB_COLORS color,unsigned char r)
{
	double i = 0;
	int x = 0,y = 0;
	TElipse E = {R->xA+r,R->yA+r,r,r};
	LCD_line(R->xA+r,R->yA,R->xC-r, R->yA,color);
	LCD_line(R->xA+r,R->yC,R->xC-r, R->yC,color);
	LCD_line(R->xA,R->yA+r,R->xA, R->yC-r,color);
	LCD_line(R->xC,R->yA+r,R->xC, R->yC-r,color);
	for (i = 1.57; i < 3.14; i+=0.001)
	{
		x = (int)(E.x+E.a*cos(i));
		y =(int)(E.y+E.b*sin(-i));
		LCD_put_pix(x,y,color);
	}
	E.y = R->yC-r;
	for (i = 1.57; i < 3.14; i+=0.001)
	{
		x = (int)(E.x+E.a*cos(i));
		y =(int)(E.y+E.b*sin(i));
		LCD_put_pix(x,y,color);
	}

	E.x = R->xC-r;
	for (i = 0; i < 1.57; i+=0.01)
	{
		x = (int)(E.x+E.a*cos(i));
		y =(int)(E.y+E.b*sin(i));

		LCD_put_pix(x,y,color);
	}
	E.y = R->yA+r;
	for (i = 0; i < 1.57; i+=0.001)
	{
		x = (int)(E.x+E.a*cos(i));
		y =(int)(E.y+E.b*sin(-i));
		LCD_put_pix(x,y,color);
	}
}

/****************************************************************************
	Vymaze platno pro kresleni a vyplni ho barvou pozadi

	Vstup: 
		není

	Výstup:
		není

*****************************************************************************/
void LCD_clear(void)
{
	TRect screen = {0,0,MAX_X-1, MAX_Y-1};
	LCD_frect(&screen,RGB_BACKGROUND);
}

/****************************************************************************
	Vykresli bitmapu

	format bitmapy je nasledujici: 

	const unsigned short image = {sirka, vyska, pixel1, pixel2, pixel3, ...};

	Funkce nema moznost zkontrolovat realne rozmery bitmapy, proto je treba, 
	aby byla bitmapa bez chyby, jinak dojde k vyjimce

	Vstup: 
		x, y:		souradnice leveho horniho rohu
		data:		ukazatel na data

	Výstup:
		není

*****************************************************************************/
void LCD_draw_bitmap(int x, int y, const unsigned short * data)
{
	const unsigned short * data_tmp = data + 2;
	for (int i = 0; i < data[0]; i++)
	{
		for (int j = 0; j < data[1]; j++)
		{
			LCD_put_RAW_pix(x+i, y+j,data_tmp[i+data[0]*j]);
		}
	}
}


/****************************************************************************
	Vykresli bitmapu stejnym zpusobem jako LCD_draw_bitmap, je vsak pridana 
	podminka pro pruhlednost. Pixely odpovidajici hodnote idnored jsou ignorovany.

	Vstup: 
		x, y:			souradnice leveho horniho rohu
		data:			ukazatel na data
		ignored:		ignorovana hodnota pixelu

	Výstup:
		není

*****************************************************************************/
void LCD_draw_bitmap_cond(int x, int y, const unsigned short * data, short ignored)
{
	const unsigned short * data_tmp = data + 2;
	for (int i = 0; i < data[0]; i++)
	{
		for (int j = 0; j < data[1]; j++)
		{
			if (data_tmp[i+data[0]*j] != ignored)
				LCD_put_RAW_pix(x+i, y+j,data_tmp[i+data[0]*j]);
		}
	}
}







