/*******************************************************************************
 *
 *      G R A P H I C S    P R I M I T I V E S
 *
 *      Copyright A Levido 2013 - All Rights Reserved
 *
 ******************************************************************************/
#include "graphics.h"

/* Draw Line */
void grLine(INT16 x1, INT16 y1, INT16 x2, INT16 y2, UINT16 colour, BOOL thick)
{
    INT16 x, y;
    INT16 dx, dy, sx, sy;
    INT16 err, e2;
    INT16 steep;

    dx = x2 >= x1 ? x2 - x1 : x1 - x2;
    dy = y2 >= y1 ? y1 - y2 : y2 - y1;
    sx = x1 < x2 ? 1 : -1;
    sy = y1 < y2 ? 1 : -1;
    err = dx + dy;
    x = x1;
    y = y1;

    steep = dx < -dy ? 0 : 1;

    while(1){
        lcdPutPixel(x, y, colour);
        if(thick == TRUE){
            if(steep){
                lcdPutPixel(x, y + 1, colour);
                lcdPutPixel(x, y - 1, colour);
            }
            else{
                lcdPutPixel(x + 1, y, colour);
                lcdPutPixel(x - 1, y, colour);
            }
        }

        if((x == x2) && (y == y2)) break;
        e2 = 2 * err;
        if(e2 >= dy){ // step x
            err += dy;
            x += sx;
        }
        if(e2 <= dx){ // step y
            err += dx;
            y += sy;
        }
    }
}

/* Draw a Box */
void grBox(INT16 x1, INT16 y1, INT16 x2, INT16 y2, UINT16 colour, BOOL thick)
 {
     grLine(x1, y1, x2, y1, colour, thick);
     grLine(x1, y1, x1, y2, colour, thick);
     grLine(x1, y2, x2, y2, colour, thick);
     grLine(x2, y1, x2, y2, colour, thick);

 }
/* Draws one or more Quadrants of a Circle */
void grQuadrants (INT16 x0, INT16 y0, INT16 r, UINT8 quadrants, UINT16 colour, BOOL thick)
{
    INT16 x, y, err, count, temp;

    x = -r;
    y = 0;
    err = 2 - (2 * r);
    count = 0;

    do {
        if(quadrants & QUADRANT_4) lcdPutPixel(x0 - x, y0 + y, colour);
        if(quadrants & QUADRANT_3) lcdPutPixel(x0 - y, y0 - x, colour);
        if(quadrants & QUADRANT_2) lcdPutPixel(x0 + x, y0 - y, colour);
        if(quadrants & QUADRANT_1) lcdPutPixel(x0 + y, y0 + x, colour);
        temp = err;
        if(temp > x) err += ++x * 2 + 1;
        if(temp <= y) err += ++y * 2 + 1;
    } while (x < 0);

    if(thick){
        x = -r - 1;
        y = 0;
        err = 2 - (2 * r);
        count = 0;

        do {
            if(quadrants & QUADRANT_4) lcdPutPixel(x0 - x, y0 + y, colour);
            if(quadrants & QUADRANT_3) lcdPutPixel(x0 - y, y0 - x, colour);
            if(quadrants & QUADRANT_2) lcdPutPixel(x0 + x, y0 - y, colour);
            if(quadrants & QUADRANT_1) lcdPutPixel(x0 + y, y0 + x, colour);
            temp = err;
            if(temp > x) err += ++x * 2 + 1;
            if(temp <= y) err += ++y * 2 + 1;
        } while (x < 0);

        x = -r + 1;
        y = 0;
        err = 2 - (2 * r);
        count = 0;

        do {
            if(quadrants & QUADRANT_4) lcdPutPixel(x0 - x, y0 + y, colour);
            if(quadrants & QUADRANT_3) lcdPutPixel(x0 - y, y0 - x, colour);
            if(quadrants & QUADRANT_2) lcdPutPixel(x0 + x, y0 - y, colour);
            if(quadrants & QUADRANT_1) lcdPutPixel(x0 + y, y0 + x, colour);
            temp = err;
            if(temp > x) err += ++x * 2 + 1;
            if(temp <= y) err += ++y * 2 + 1;
        } while (x < 0);
    }

}
/*  Draws a rounded rectangle */
void grRoundRect (INT16 x0, INT16 y0, INT16 x1, INT16 y1, INT16 r, UINT16 colour, BOOL thick)
{
    INT16 x, y, err, count, temp;

    x0 += r;
    y0 += r;
    x1 -= r;
    y1 -= r;

    grLine(x0, y0 - r, x1, y0 - r, colour, thick);
    grLine(x0, y1 + r, x1, y1 + r, colour, thick);
    grLine(x0 - r, y0, x0 - r, y1, colour, thick);
    grLine(x1 + r, y0, x1 + r, y1, colour, thick);

    x = -r;
    y = 0;
    err = 2 - (2 * r);
    count = 0;

    do {
        lcdPutPixel(x1 - x, y1 + y, colour);
        lcdPutPixel(x0 - y, y1 - x, colour);
        lcdPutPixel(x0 + x, y0 - y, colour);
        lcdPutPixel(x1 + y, y0 + x, colour);
        temp = err;
        if(temp > x) err += ++x * 2 + 1;
        if(temp <= y) err += ++y * 2 + 1;
    } while (x < 0);

    if(thick){
        x = -r - 1;
        y = 0;
        err = 2 - (2 * r);
        count = 0;

        do {
            lcdPutPixel(x1 - x, y1 + y, colour);
            lcdPutPixel(x0 - y, y1 - x, colour);
            lcdPutPixel(x0 + x, y0 - y, colour);
            lcdPutPixel(x1 + y, y0 + x, colour);
            temp = err;
            if(temp > x) err += ++x * 2 + 1;
            if(temp <= y) err += ++y * 2 + 1;
        } while (x < 0);

        x = -r + 1;
        y = 0;
        err = 2 - (2 * r);
        count = 0;

        do {
            lcdPutPixel(x1 - x, y1 + y, colour);
            lcdPutPixel(x0 - y, y1 - x, colour);
            lcdPutPixel(x0 + x, y0 - y, colour);
            lcdPutPixel(x1 + y, y0 + x, colour);
            temp = err;
            if(temp > x) err += ++x * 2 + 1;
            if(temp <= y) err += ++y * 2 + 1;
        } while (x < 0);
    }
}

/* Draws one or more Filled Quadrants of a Circle */
void grFilledQuadrants (INT16 x0, INT16 y0, INT16 r, UINT8 quadrants, UINT16 colour)
{
    INT16 x, y, err;

    x = -r;
    y = 0;
    err = 2 - (2 * r);
    do {
        if(quadrants & QUADRANT_4) grLine(x0 - x, y0 + y, x0, y0 + y, colour, 0);
        if(quadrants & QUADRANT_3) grLine(x0 - y, y0 - x, x0, y0 - x, colour, 0);
        if(quadrants & QUADRANT_2) grLine(x0 + x, y0 - y, x0, y0 - y, colour, 0);
        if(quadrants & QUADRANT_1) grLine(x0 + y, y0 + x, x0, y0 + x, colour, 0);
        r = err;
        if(r > x) err += ++x * 2 + 1;
        if(r <= y) err += ++y * 2 + 1;
    } while (x < 0);
}
/*********************************************************************
 * Draws a filled rounded rectangle
 */
void grFilledRoundRect(SHORT x0, SHORT y0, SHORT x1, SHORT y1, SHORT r, UINT16 colour)
{
    INT16 x, y, err;

    x0 += r;
    y0 += r;
    x1 -= r;
    y1 -= r;
    grBlock(x0, y0 - r, x1, y0, colour);
    grBlock(x0 - r, y0, x1 + r, y1, colour);
    grBlock(x0, y1, x1, y1 + r, colour);

    x = -r;
    y = 0;
    err = 2 - (2 * r);
    do {
        grLine(x1 - x, y1 + y, x1, y1 + y, colour, 0);
        grLine(x0 - y, y1 - x, x0, y1 - x, colour, 0);
        grLine(x0 + x, y0 - y, x0, y0 - y, colour, 0);
        grLine(x1 + y, y0 + x, x1, y0 + x, colour, 0);
        r = err;
        if(r > x) err += ++x * 2 + 1;
        if(r <= y) err += ++y * 2 + 1;
    } while (x < 0);
}


////// Draw Text   /////////////////////////////////////////////////////////////

UINT16 cBuff[16];

void grText(UINT16 x1, UINT16 y1, UINT16 col, UINT16 bg, const UINT16 const* f[], BOOL c, char* str)
{

    UINT16 cursor;
    char* t;
    UINT16 height, width;
    UINT16 space;
    const UINT16* pglyph;
    UINT16 mask;
    UINT16 dy;
    UINT16 i;

   /* data */
    pglyph = f[0];
    height = pglyph[0];
    space = pglyph[1];

    if(c == TRUE){
        width = 0;
        t = str;
        while(*t){
            if((*str < ' ') || (*str > '~')) return;
            pglyph = f[*t - ' ' + 1];
            width += pglyph[0];
            width += space;
            t++;
        }
        width -= space;
        x1 = x1 - (width / 2);
        y1 = y1 - (height / 2);
    }
    cursor = x1;

    /* For each char */
    while(*str){
        pglyph = f[*str - ' ' + 1];
        width = pglyph[0];
        /* For each vertical slice */
//        for(i = 1; i <= width; i++){
//            mask = 1;
//            for(dy = 0; dy < height; dy++){
//                if(mask & pglyph[i]) { lcdPutPixel(cursor, y1 + dy, col); }
//                else { lcdPutPixel(cursor, y1 + dy, bg); }
//                mask = mask << 1;
//            }
//            cursor++;
//        }
        lcdRender(cursor, y1, width, height, col, bg, pglyph);
        cursor += width;
        /* Spaces */
        for (i = 0; i < space; i++){
            for(dy = 0; dy < height; dy++) { lcdPutPixel(cursor, y1 + dy, bg); }
            cursor++;
        }
        str++;
    }
}

UINT16 grGetHeight(FONT font[])
{
    const UINT16* pglyph = font[0];
    return pglyph[0];
}

UINT16 grGetWidth(FONT font[], char* text)
{
    const UINT16* pglyph = font[0];
    UINT16 width = 0;
    UINT16 space;

    space = pglyph[1];
    while(*text){
        if((*text < ' ') || (*text > '~')) return;
        pglyph = font[*text - ' ' + 1];
        width += pglyph[0];
        width += space;
        text++;
    }
}
UINT16 grFit(FONT font[], char* text, INT16 width)
{
    const UINT16* pglyph = font[0];
    UINT16 count = 0;
    UINT16 space;

    space = pglyph[1];
    while(*text){
        if((*text < ' ') || (*text > '~')) return count;
        pglyph = font[*text - ' ' + 1];
        width -= pglyph[0];
        if(width <= 0) return count;
        width -= space;
        if(width <= 0) return count;
        text++;
        count++;
    }
    return count;
}

/* Draw and Icon */
//void grIcon(UINT16 x1, UINT16 y1, UINT16 col, UINT16 bg, const UINT8 icon[])
//{
//    UINT16 i, j;
//    UINT32 temp, mask;
//
//    x1 = x1 - 12;
//    y1 = y1 - 12;
//    /* for each horizontal slice i */
//    for(i = 0; i < 24; i++){
//        temp = icon[3 * i];
//        temp |= (icon[3 * i + 1] << 8);
//        temp |= (icon[3 * i + 2] << 16);
//        mask = 1;
//
//        /* for each bit in the slice j */
//        for(j = 0;  j < 24; j++){
//               if(mask & temp) { lcdPutPixel(x1 + j, y1 + i, col); }
//                else { lcdPutPixel(x1 + j, y1 + i, bg); }
//               mask = mask << 1;
//        }
//    }
//}


