#include "stm32f10x_lib.h"
#include "stdio.h"
#include "T6963C.h"
#include "GRAPH.h"



/* Extern functions ------------------------------------------------------------- */
extern void WINDOWS_SetPixel(unsigned char x, unsigned char y, unsigned int color);
extern void WINDOWS_WriteData(unsigned char cIn);
extern void WINDOWS_ClearScreen(void);

/* Private variables ---------------------------------------------------------*/
#define BLACK 0x00
#define WHITE 0xFF

unsigned char screen_x = 0, screen_y = 0; // screen coordinates
static unsigned char Line=0;
static unsigned char Cursor=0;
static unsigned char u8CursorOn=0;
static unsigned char u8BlackWhite=WHITE;


inline void GRAPH_SetPixel(unsigned char x, unsigned char y, unsigned int color){
GLCD_SetPixel(x,y,color);
}

unsigned char GRAPH_ReadByteFromROMMemory(volatile char * ptr)
{
	if(u8BlackWhite==WHITE){
		return ~(*(ptr));
	}else{
		return *(ptr);
	}
}

void GRAPH_TextGoTo(unsigned char x, unsigned char y)
{
    Cursor=x;
    Line=y;
    
    GLCD_Text_GoTo(x,y);
}

void GRAPH_ClearScreen(void)
{
    GLCD_Clear_Text();
    GLCD_Clear_CG();
    GLCD_Clear_Graphic();
}


void GRAPH_WriteChar(char charToWrite)
{
char i;
static char Slash=0;
switch(charToWrite){
   case '\f':
      GRAPH_ClearScreen();
      Line=0;
      Cursor=0;
      GRAPH_TextGoTo(Cursor,Line);
   break;
   
   case '\n':
      Line++;	
      GRAPH_TextGoTo(Cursor,Line);
   break;
   
   case '\r':
      Cursor=0;
      GRAPH_TextGoTo(Cursor,Line);
   break;
   

   default:
      if(u8BlackWhite==WHITE){
        /* Set for t6963c */
        GLCD_Write_Command(T6963_MODE_SET | T6963_MODE_SET_XOR);      
        GRAPH_RectangleFilled(Cursor*6, Line*8, 6, 8,1);         
        GRAPH_TextGoTo(Cursor,Line);     
        GLCD_Write_Char(charToWrite);       
      }else{
        /* Set for t6963c */
        GLCD_Write_Command(T6963_MODE_SET | T6963_MODE_SET_OR);  
        GRAPH_RectangleFilled(Cursor*6, Line*8, 6, 8,0);    
        GRAPH_TextGoTo(Cursor,Line); 
        GLCD_Write_Char(charToWrite);        
      }
      
      Cursor++;
   break;
}
}


void GRAPH_BlackWhite(void){
    u8BlackWhite=WHITE;
}
void GRAPH_WhiteBlack(void){
    u8BlackWhite=BLACK;
}
//-------------------------------------------------------------------------------------------------
// (c) Radosław Kwiecień, radek@dxp.pl
//-------------------------------------------------------------------------------------------------
void GRAPH_Rectangle(unsigned char x, unsigned char y, unsigned char b, unsigned char a,char color)
{
  unsigned char j; // zmienna pomocnicza
  // rysowanie linii pionowych (boki)
  for (j = 0; j < a; j++) {
		GRAPH_SetPixel(x, y + j, color);
		GRAPH_SetPixel(x + b - 1, y + j, color);
	}
  // rysowanie linii poziomych (podstawy)
  for (j = 0; j < b; j++)	{
		GRAPH_SetPixel(x + j, y, color);
		GRAPH_SetPixel(x + j, y + a - 1, color);
	}
}

void GRAPH_RectangleFilled(unsigned char x, unsigned char y, unsigned char b, unsigned char a,char color)
{
    unsigned char j; // zmienna pomocnicza
    unsigned char k;

    // rysowanie linii pionowych (boki)
    for (j = 0; j < a; j++){
        if((b/6)==0){
            for(k = 0; k < b; k++){
            GRAPH_SetPixel(x + k, y + j, color);
            }         
        }else{
            GLCD_GoTo(x,y + j);
            for(k = 0; k < (b/6); k++){
                if(color){
                    GLCD_Write8Pixels(0xFF);
                }else{
                    GLCD_Write8Pixels(0x00);            
                }
            }    
            //for(k=((b/6)*6);k<b;k++){
            //    GRAPH_SetPixel(x + k, y + j,color);            
            //}
        }
    }
}

//-------------------------------------------------------------------------------------------------
//
//-------------------------------------------------------------------------------------------------
void GRAPH_Circle(unsigned char cx, unsigned char cy ,unsigned char radius,char color)
{
int x, y, xchange, ychange, radiusError;
x = radius;
y = 0;
xchange = 1 - 2 * radius;
ychange = 1;
radiusError = 0;
while(x >= y)
  {
  GRAPH_SetPixel(cx+x, cy+y, color); 
  GRAPH_SetPixel(cx-x, cy+y, color); 
  GRAPH_SetPixel(cx-x, cy-y, color);
  GRAPH_SetPixel(cx+x, cy-y, color); 
  GRAPH_SetPixel(cx+y, cy+x, color); 
  GRAPH_SetPixel(cx-y, cy+x, color); 
  GRAPH_SetPixel(cx-y, cy-x, color);
  GRAPH_SetPixel(cx+y, cy-x, color); 
  y++;
  radiusError += ychange;
  ychange += 2;
  if ( 2*radiusError + xchange > 0 )
    {
    x--;
	radiusError += xchange;
	xchange += 2;
	}
  }
}
//-------------------------------------------------------------------------------------------------
//
//-------------------------------------------------------------------------------------------------
void GRAPH_Line(int X1, int Y1,int X2,int Y2, char color)
{
int CurrentX, CurrentY, Xinc, Yinc, 
    Dx, Dy, TwoDx, TwoDy, 
	TwoDxAccumulatedError, TwoDyAccumulatedError;

Dx = (X2-X1); // obliczenie składowej poziomej
Dy = (Y2-Y1); // obliczenie składowej pionowej

TwoDx = Dx + Dx; // podwojona składowa pozioma
TwoDy = Dy + Dy; // podwojona składowa pionowa

CurrentX = X1; // zaczynamy od X1
CurrentY = Y1; // oraz Y1

Xinc = 1; // ustalamy krok zwiększania pozycji w poziomie 
Yinc = 1; // ustalamy krok zwiększania pozycji w pionie

if(Dx < 0) // jesli składowa pozioma jest ujemna 
  {
  Xinc = -1; // to będziemy się "cofać" (krok ujemny)
  Dx = -Dx;  // zmieniamy znak składowej na dodatni
  TwoDx = -TwoDx; // jak również podwojonej składowej
  }

if (Dy < 0) // jeśli składowa pionowa jest ujemna
  {
  Yinc = -1; // to będziemy się "cofać" (krok ujemny)
  Dy = -Dy; // zmieniamy znak składowej na dodatki
  TwoDy = -TwoDy; // jak równiez podwojonej składowej
  }

GRAPH_SetPixel(X1,Y1, color); // stawiamy pierwszy krok (zapalamy pierwszy piksel)

if ((Dx != 0) || (Dy != 0)) // sprawdzamy czy linia składa się z więcej niż jednego punktu ;)
  {
  // sprawdzamy czy składowa pionowa jest mniejsza lub równa składowej poziomej
  if (Dy <= Dx) // jeśli tak, to idziemy "po iksach"
    { 
    TwoDxAccumulatedError = 0; // zerujemy zmienną 
    do // ruszamy w drogę
	  {
      CurrentX += Xinc; // do aktualnej pozycji dodajemy krok 
      TwoDxAccumulatedError += TwoDy; // a tu dodajemy podwojoną składową pionową
      if(TwoDxAccumulatedError > Dx)  // jeśli TwoDxAccumulatedError jest większy od Dx
        {
        CurrentY += Yinc; // zwiększamy aktualną pozycję w pionie
        TwoDxAccumulatedError -= TwoDx; // i odejmujemy TwoDx
        }
       GRAPH_SetPixel(CurrentX,CurrentY, color);// stawiamy następny krok (zapalamy piksel)
       }while (CurrentX != X2); // idziemy tak długo, aż osiągniemy punkt docelowy
     }
   else // w przeciwnym razie idziemy "po igrekach" 
      {
      TwoDyAccumulatedError = 0; 
      do 
	    {
        CurrentY += Yinc; 
        TwoDyAccumulatedError += TwoDx;
        if(TwoDyAccumulatedError>Dy) 
          {
          CurrentX += Xinc;
          TwoDyAccumulatedError -= TwoDy;
          }
         GRAPH_SetPixel(CurrentX,CurrentY, color); 
         }while (CurrentY != Y2);
    }
  }
}
//-------------------------------------------------------------------------------------------------
//
//-------------------------------------------------------------------------------------------------
void GRAPH_SquareRotated(int iX0,int iY0,int iX1,int iY1,int iX2,int iY2, float iRotation, char color){
  unsigned char j; 
  float fx,fy;
  int ix,iy;
  for (j = iX1; j < (iX2+1); j++) {
		fx=(float)j;
		fy=(float)iY1;
		fx=(fx*cos(iRotation))-(fy*sin(iRotation));
		fy=(fx*sin(iRotation))+(fy*cos(iRotation));
		ix=(int)fx+iX0;
		iy=(int)fy+iY0;
		GRAPH_SetPixel(ix, iy, color);
		fx=(float)j;
		fy=(float)iY2;
		fx=(fx*cos(iRotation))-(fy*sin(iRotation));
		fy=(fx*sin(iRotation))+(fy*cos(iRotation));
		ix=(int)fx+iX0;
		iy=(int)fy+iY0;
		GRAPH_SetPixel(ix, iy, color);
	}
  
  for (j = iY1; j < (iY2+1); j++)	{
		fx=(float)iX1;
		fy=(float)j;
		fx=(fx*cos(iRotation))-(fy*sin(iRotation));
		fy=(fx*sin(iRotation))+(fy*cos(iRotation));
		ix=(int)fx+iX0;
		iy=(int)fy+iY0;
		GRAPH_SetPixel(ix, iy, color);
		fx=(float)iX2;
		fy=(float)j;
		fx=(fx*cos(iRotation))-(fy*sin(iRotation));
		fy=(fx*sin(iRotation))+(fy*cos(iRotation));
		ix=(int)fx+iX0;
		iy=(int)fy+iY0;
		GRAPH_SetPixel(ix, iy, color);
	}	
}


void GRAPH_Arrow(int iX0,int iY0,int iX1,int iY1, char color){
	POINT pFrom= {iX0, iY0};
	POINT pBase;
	POINT aptPoly[3];
	float vecLine[2];
	float vecLeft[2];
	float fLength;
	float th;
	float ta;
	POINT lpTo = {iX1, iY1};
	ARROWSTRUCT ArrowHead;
	ArrowHead.fTheta=20;
	ArrowHead.bFill=1;
	ArrowHead.nWidth=10;

	// get from point
	//MoveToEx(hDC, 0, 0, &pFrom);

	// set to point
	aptPoly[0].x = lpTo.x;
	aptPoly[0].y = lpTo.y;

	// build the line vector
	vecLine[0] = (float) aptPoly[0].x - pFrom.x;
	vecLine[1] = (float) aptPoly[0].y - pFrom.y;

	// build the arrow base vector - normal to the line
	vecLeft[0] = -vecLine[1];
	vecLeft[1] = vecLine[0];

	// setup length parameters
	fLength = (float) sqrt(vecLine[0] * vecLine[0] + vecLine[1] * vecLine[1]);
	th = ArrowHead.nWidth / (2.0f * fLength);
	ta = ArrowHead.nWidth / (2.0f * (tanf(ArrowHead.fTheta) / 2.0f) * fLength);

	// find the base of the arrow
	pBase.x = (int) (aptPoly[0].x + -ta * vecLine[0]);
	pBase.y = (int) (aptPoly[0].y + -ta * vecLine[1]);

	// build the points on the sides of the arrow
	aptPoly[1].x = (int) (pBase.x + th * vecLeft[0]);
	aptPoly[1].y = (int) (pBase.y + th * vecLeft[1]);
	aptPoly[2].x = (int) (pBase.x + -th * vecLeft[0]);
	aptPoly[2].y = (int) (pBase.y + -th * vecLeft[1]);

//	MoveToEx(hDC, pFrom.x, pFrom.y, NULL);

	// draw we're fillin'...
	if(ArrowHead.bFill) {
		//GRAPH_Line(pFrom.x,pFrom.y,aptPoly[0].x, aptPoly[0].y,color);
		GRAPH_TriangleFill(aptPoly,3,1);
		//GRAPH_Line(aptPoly[0].x,aptPoly[0].y,aptPoly[1].x, aptPoly[1].y,1);
		//GRAPH_Line(aptPoly[1].x,aptPoly[1].y,aptPoly[2].x, aptPoly[2].y,1);
		//GRAPH_Line(aptPoly[2].x,aptPoly[2].y,aptPoly[0].x, aptPoly[0].y,1);
	}

	// ... or even jes chillin'...
	else {
		GRAPH_Line(pFrom.x,pFrom.y,pBase.x, pBase.y,color);
		GRAPH_Line(pFrom.x,pFrom.y,aptPoly[1].x, aptPoly[1].y,color);
		GRAPH_Line(pFrom.x,pFrom.y,aptPoly[0].x, aptPoly[0].y,color);
		GRAPH_Line(pFrom.x,pFrom.y,aptPoly[2].x, aptPoly[2].y,color);
		GRAPH_Line(pFrom.x,pFrom.y,pBase.x, pBase.y,color);

		//MoveToEx(hDC, aptPoly[0].x, aptPoly[0].y, NULL);

	}
}



void GRAPH_TriangleFill(POINT *pPoints,int size,int color){

float dx1,dx2,dx3;
POINT A,B,C;
POINT S;
POINT E;
POINT Buble;
int i=0;
	

//Bubble sort;

	for(i=0;i<(size-1);i++){
		if(pPoints[i].y < pPoints[i+1].y){
			Buble=pPoints[i];
			pPoints[i]=pPoints[i+1];
			pPoints[i+1]=Buble;
		}
	}
	C=pPoints[0];
	B=pPoints[1];
	A=pPoints[2];
	
	
	if (B.y-A.y > 0) dx1=((float)(B.x-A.x)/(float)(B.y-A.y)); else dx1=0;
	if (C.y-A.y > 0) dx2=((float)(C.x-A.x)/(float)(C.y-A.y)); else dx2=0;
	if (C.y-B.y > 0) dx3=((float)(C.x-B.x)/(float)(C.y-B.y)); else dx3=0;

	S=E=A;

	if(dx1 > dx2) {
		for(;S.y<=B.y;S.y++,E.y++,S.x+=dx2,E.x+=dx1)
			GRAPH_Line(S.x,S.y,E.x,S.y,color);
		E=B;
		for(;S.y<=C.y;S.y++,E.y++,S.x+=dx2,E.x+=dx3)
			GRAPH_Line(S.x,S.y,E.x,S.y,color);
	} else {
		for(;S.y<=B.y;S.y++,E.y++,S.x+=dx1,E.x+=dx2)
			GRAPH_Line(S.x,S.y,E.x,S.y,color);
		S=B;
		for(;S.y<=C.y;S.y++,E.y++,S.x+=dx3,E.x+=dx2)
			GRAPH_Line(S.x,S.y,E.x,S.y,color);
	}

}

