#include "gui.h"

void drawFastHLine(gui_int16 x, gui_int16 y, gui_int16 w, gui_color color)
{
	fillRect(x,y,w,1,color);
}

void drawFastVLine(gui_int16 x, gui_int16 y, gui_int16 h, gui_color color)
{
	fillRect(x,y,1,h,color);
}

void drawLine(gui_int16 x0, gui_int16 y0, gui_int16 x1, gui_int16 y1, 
		gui_color color)
{
  gui_int16 steep; 
	gui_int16 dx, dy;
	gui_int16 ystep;
	gui_int16 err;
	steep = abs(y1 - y0) > abs(x1 - x0);
  if (steep) {
    swap(x0, y0);
    swap(x1, y1);
  }

  if (x0 > x1) {
    swap(x0, x1);
    swap(y0, y1);
  }

  dx = x1 - x0;
  dy = abs(y1 - y0);

  err = dx / 2;

  if (y0 < y1) {
    ystep = 1;
  } else {
    ystep = -1;
  }
  for (; x0<=x1; x0++) 
  {
    if (steep) 
    {
      drawPixel(y0, x0, color);
    } 
    else 
    {
      drawPixel(x0, y0, color);
    }
    err -= dy;
    if (err < 0) 
    {
      y0 += ystep;
      err += dx;
    }
  }
}

void drawRect(gui_int16 x, gui_int16 y, gui_int16 w, gui_int16 h, gui_color color)
{
	drawFastHLine(x,y,w,color);
	drawFastHLine(x,y+h,w,color);
	drawFastVLine(x,y,h,color);
	drawFastVLine(x+w,y,h,color);
}

void fillScreen(gui_color color)
{
	fillRect(0,0,LCD_WIDE,LCD_HEIGHT,color);
}

void drawCircleHelper(gui_int16 x0, gui_int16 y0,gui_int16 r, gui_int8 cornername, 
		gui_color color)
{
	gui_int16 f     = 1 - r;
  gui_int16 ddF_x = 1;
  gui_int16 ddF_y = -2 * r;
  gui_int16 x     = 0;
  gui_int16 y     = r;

  while (x<y) {
    if (f >= 0) {
      y--;
      ddF_y += 2;
      f     += ddF_y;
    }
    x++;
    ddF_x += 2;
    f     += ddF_x;
    if (cornername & 0x4) {
      drawPixel(x0 + x, y0 + y, color);
      drawPixel(x0 + y, y0 + x, color);
    } 
    if (cornername & 0x2) {
      drawPixel(x0 + x, y0 - y, color);
      drawPixel(x0 + y, y0 - x, color);
    }
    if (cornername & 0x8) {
      drawPixel(x0 - y, y0 + x, color);
      drawPixel(x0 - x, y0 + y, color);
    }
    if (cornername & 0x1) {
      drawPixel(x0 - y, y0 - x, color);
      drawPixel(x0 - x, y0 - y, color);
    }
  }
}

void drawCircle(gui_int16 x0, gui_int16 y0, gui_int16 r, gui_color color)
{
	gui_int16 f = 1 - r;
  gui_int16 ddF_x = 1;
  gui_int16 ddF_y = -2 * r;
  gui_int16 x = 0;
  gui_int16 y = r;

  drawPixel(x0, y0+r, color);
  drawPixel(x0, y0-r, color);
  drawPixel(x0+r, y0, color);
  drawPixel(x0-r, y0, color);

  while (x<y) {
    if (f >= 0) {
      y--;
      ddF_y += 2;
      f += ddF_y;
    }
    x++;
    ddF_x += 2;
    f += ddF_x;
  
    drawPixel(x0 + x, y0 + y, color);
    drawPixel(x0 - x, y0 + y, color);
    drawPixel(x0 + x, y0 - y, color);
    drawPixel(x0 - x, y0 - y, color);
    drawPixel(x0 + y, y0 + x, color);
    drawPixel(x0 - y, y0 + x, color);
    drawPixel(x0 + y, y0 - x, color);
    drawPixel(x0 - y, y0 - x, color);   
  }
}

void fillCircleHelper(gui_int16 x0, gui_int16 y0, gui_int16 r,
		      gui_int8 cornername, gui_int16 delta, gui_color color)
{
	gui_int16 f     = 1 - r;
  gui_int16 ddF_x = 1;
  gui_int16 ddF_y = -2 * r;
  gui_int16 x     = 0;
  gui_int16 y     = r;

  while (x<y) {
    if (f >= 0) {
      y--;
      ddF_y += 2;
      f     += ddF_y;
    }
    x++;
    ddF_x += 2;
    f     += ddF_x;

    if (cornername & 0x1) {
      drawFastVLine(x0+x, y0-y, 2*y+1+delta, color);
      drawFastVLine(x0+y, y0-x, 2*x+1+delta, color);
    }
    if (cornername & 0x2) {
      drawFastVLine(x0-x, y0-y, 2*y+1+delta, color);
      drawFastVLine(x0-y, y0-x, 2*x+1+delta, color);
    }
  }
}

void fillCircle(gui_int16 x0, gui_int16 y0, gui_int16 r, gui_color color)
{
	drawFastVLine(x0, y0-r, 2*r+1, color);
  fillCircleHelper(x0, y0, r, 3, 0, color);
}

void drawTriangle(gui_int16 x0, gui_int16 y0, gui_int16 x1, gui_int16 y1,
		    gui_int16 x2, gui_int16 y2, gui_color color)
{
	drawLine(x0, y0, x1, y1, color);
  drawLine(x1, y1, x2, y2, color);
  drawLine(x2, y2, x0, y0, color);
}

void fillTriangle(gui_int16 x0, gui_int16 y0, gui_int16 x1, gui_int16 y1,
		    gui_int16 x2, gui_int16 y2, gui_color color)
{
	gui_int16 a, b, y, last;
	
	gui_int16
    dx01 = x1 - x0,
    dy01 = y1 - y0,
    dx02 = x2 - x0,
    dy02 = y2 - y0,
    dx12 = x2 - x1,
    dy12 = y2 - y1,
    sa   = 0,
    sb   = 0;

  // Sort coordinates by Y order (y2 >= y1 >= y0)
  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) { // Handle awkward all-on-same-line case as its own thing
    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;
    drawFastHLine(a, y0, b-a+1, color);
    return;
  }

  // For upper part of triangle, find scanline crossings for segments
  // 0-1 and 0-2.  If y1=y2 (flat-bottomed triangle), the scanline y1
  // is included here (and second loop will be skipped, avoiding a /0
  // error there), otherwise scanline y1 is skipped here and handled
  // in the second loop...which also avoids a /0 error here if y0=y1
  // (flat-topped triangle).
  if(y1 == y2) last = y1;   // Include y1 scanline
  else         last = y1-1; // Skip it

  for(y=y0; y<=last; y++) {
    a   = x0 + sa / dy01;
    b   = x0 + sb / dy02;
    sa += dx01;
    sb += dx02;
    /* longhand:
    a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
    b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
    */
    if(a > b) swap(a,b);
    drawFastHLine(a, y, b-a+1, color);
  }

  // For lower part of triangle, find scanline crossings for segments
  // 0-2 and 1-2.  This loop is skipped if y1=y2.
  sa = dx12 * (y - y1);
  sb = dx02 * (y - y0);
  for(; y<=y2; y++) {
    a   = x1 + sa / dy12;
    b   = x0 + sb / dy02;
    sa += dx12;
    sb += dx02;
    /* longhand:
    a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
    b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
    */
    if(a > b) swap(a,b);
    drawFastHLine(a, y, b-a+1, color);
  }
}

void drawRoundRect(gui_int16 x0, gui_int16 y0, gui_int16 w, gui_int16 h,
		     gui_int16 radius, gui_color color)
{
	 // smarter version
  drawFastHLine(x0+radius  , y0    , w-2*radius, color); // Top
  drawFastHLine(x0+radius  , y0+h-1, w-2*radius, color); // Bottom
  drawFastVLine(x0    , y0+radius  , h-2*radius, color); // Left
  drawFastVLine(x0+w-1, y0+radius  , h-2*radius, color); // Right
  // draw four corners
  drawCircleHelper(x0+radius    , y0+radius    , radius, 1, color);
  drawCircleHelper(x0+w-radius-1, y0+radius    , radius, 2, color);
  drawCircleHelper(x0+w-radius-1, y0+h-radius-1, radius, 4, color);
  drawCircleHelper(x0+radius   , y0+h-radius-1, radius, 8, color);
}

void fillRoundRect(gui_int16 x0, gui_int16 y0, gui_int16 w, gui_int16 h,
		     gui_int16 radius, gui_color color)
{
	// smarter version
  fillRect(x0+radius, y0, w-2*radius, h, color);

  // draw four corners
  fillCircleHelper(x0+w-radius-1, y0+radius, radius, 1, h-2*radius-1, color);
  fillCircleHelper(x0+radius    , y0+radius, radius, 2, h-2*radius-1, color);
}

gui_color RGB(gui_uint16 r,gui_uint16 g , gui_uint16 b)
{
	gui_uint16 rgb = 0;
	r *= 31;
	r /= 255;
	
	g *= 63;
	g /= 255;
	
	b *= 31;
	b /= 255;
	
	rgb |= (r<<11);
	rgb |= (g<<6);
	rgb |= b;
	return rgb;
}

