Subversion Repositories group.electronics

Rev

Rev 128 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * gfx.c
 *
 *  Created on: 28/11/2013
 *      Author: pfowler
 */

#include <avr/io.h>
#include <stdlib.h>
#include <avr/pgmspace.h>
#include <string.h>

#include "avrutil.h"
#include "gfx.h"


void gfx_init(uint8_t* buffer, uint8_t width, uint8_t height) {
        gfx.width = width;
        gfx.height = height;
        gfx.buffer = buffer;

        gfx_font.cursor_x = 0;
        gfx_font.cursor_y = 0;
        gfx_font.textsize = 1;
        gfx_font.textcolor = 1;
        gfx_font.textbgcolor = 1;
        gfx_font.wrap = 1;
}

uint8_t gfx_getRotation(void) {
        return gfx.rotation;
}

void gfx_setRotation(uint8_t x) {
        gfx.rotation = (x & 3);
        uint8_t ow = gfx.width;
        uint8_t oh = gfx.height;

        switch(gfx.rotation) {
                case 0:
                case 2:
                        gfx.width  = ow;
                        gfx.height = oh;
                        break;
                case 1:
                case 3:
                        gfx.width  = oh;
                        gfx.height = ow;
                        break;
        }
}

void gfx_setDrawFunc(pixelptr ptr) {
        gfx.drawPixel = ptr;
}

void gfx_setFlipFunc(flipptr ptr) {
        gfx.flip = ptr;
}

void gfx_flip(void) {
        (*gfx.flip)();
}

void gfx_clear(void) {
        memset(gfx.buffer, 0x00, (gfx.width * gfx.height / 8));
}

void gfx_drawPixel(uint16_t x, uint16_t y, uint8_t color) {
        if (gfx.drawPixel) {
                (*gfx.drawPixel)(gfx.buffer, x, y, color);
                return;
        }

        if (color)
                gfx.buffer[x+ (y/8)*gfx.width] |= _BV((y%8));
        else
                gfx.buffer[x+ (y/8)*gfx.width] &= ~_BV((y%8));
}

void gfx_drawFastVLine(uint8_t x, uint8_t y, uint8_t h, uint8_t color) {
        gfx_drawLine(x, y, x, y+h-1, color);
}

void gfx_drawFastHLine(uint8_t x, uint8_t y, uint8_t w, uint8_t color) {
        gfx_drawLine(x, y, x+w-1, y, color);
}

void gfx_drawRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color) {
        gfx_drawFastHLine(x, y, w, color);
        gfx_drawFastHLine(x, y+h-1, w, color);
        gfx_drawFastVLine(x, y, h, color);
        gfx_drawFastVLine(x+w-1, y, h, color);
}

void gfx_fillRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color) {
        uint8_t i;
        for (i=x; i<x+w; i++) {
                gfx_drawFastVLine(i, y, h, color);
        }
}

void gfx_fillScreen(uint8_t color) {
        gfx_fillRect(0, 0, gfx.width, gfx.height, 1);
}

void gfx_drawLine(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t color) {
        int8_t steep = abs(y1 - y0) > abs(x1 - x0);
        //uint8_t t = 0;
        if (steep) {
                swapu(&x0, &y0);
                swapu(&x1, &y1);
        }

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

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

        int8_t err = dx /2;
        int8_t ystep;

        if (y0 < y1)
                ystep = 1;
        else
                ystep = -1;

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

void gfx_drawChar(uint8_t x, uint8_t y, unsigned char c, uint8_t color, uint8_t bg, uint8_t size) {
        if((x >= gfx.width)             || // Clip right
                (y >= gfx.height)           || // Clip bottom
                ((x + 6 * size - 1) < 0) || // Clip left
                ((y + 8 * size - 1) < 0))   // Clip top
                return;

        uint8_t i;
        for (i=0; i<6; i++) {
                uint8_t line;
                if (i == 5)
                        line = 0x0;
                else
                        line = pgm_read_byte(gfx_font_data + (c*5)+i);

                uint8_t j;
                for (j=0; j<8; j++) {
                        if (line & 0x01) {
                                if (size == 1)
                                        gfx_drawPixel(x+i, y+j, color);
                                else
                                        gfx_fillRect(x+(i*size), y+(j*size), size, size, color);
                        } else if (bg != color) {
                                if (size==1)
                                        gfx_drawPixel(x+i, y+j, bg);
                                else
                                        gfx_fillRect(x+i*size, y+j*size, size, size, bg);
                        }
                        line >>= 1;
                }
        }
}

void gfx_writec(uint8_t c) {
        if (c == '\n') {
                gfx_font.cursor_y += gfx_font.textsize*8;
                gfx_font.cursor_x = 0;
        } else if (c == '\r') {

        } else {
                gfx_drawChar(gfx_font.cursor_x, gfx_font.cursor_y, c,
                                gfx_font.textcolor, gfx_font.textbgcolor, gfx_font.textsize);
                gfx_font.cursor_x += gfx_font.textsize * 6;

                if (gfx_font.wrap &&
                                (gfx_font.cursor_x > (gfx.width - gfx_font.textsize*6))) {
                        gfx_font.cursor_y += gfx_font.textsize = 8;
                        gfx_font.cursor_x = 0;
                }
        }
}

void gfx_writeb(uint8_t *buffer, size_t size) {
        while (size--)
                gfx_writec(*buffer++);
}

void gfx_writes(char* s) {
        while (*s)
                gfx_writec(*s++);
}

void gfx_printNumber(unsigned long n, uint8_t base) {
        unsigned char buf[8 * sizeof(long)];
        unsigned long i = 0;

        if (n==0) {
                gfx_writec('0');
                return;
        }

        while (n > 0) {
                buf[i++] = n % base;
                n /= base;
        }

        for (; i>0; i--)
                gfx_writec((buf[i-1]<10) ?
                                '0' + buf[i-1] :
                                'A' + buf[i-1]-10);
}

void gfx_printFloat(double number, uint8_t digits) {
        if (number < 0.0) {
                gfx_writec('-');
                number = -number;
        }

        double rounding = 0.5;
        uint8_t i;
        for (i=0; i<digits; ++i)
                rounding /= 10.0;

        number += rounding;

        unsigned long int_part = (unsigned long)number;
        double remainder = number - (double)int_part;
        gfx_printNumber(int_part, 10);

        if (digits > 0)
                gfx_writec('.');

        while (digits-- > 0) {
                remainder *= 10.0;
                unsigned long toPrint = (unsigned long)remainder;
                gfx_printNumber(toPrint, 10);
                remainder -= toPrint;

        }
}

void gfx_setCursor(uint8_t x, uint8_t y) {
        gfx_font.cursor_x = x;
        gfx_font.cursor_y = y;
}

void gfx_setTextSize(uint8_t s) {
        gfx_font.textsize = (s>0)? s : 1;
}

void gfx_setTextColor(uint8_t c) {
        gfx_font.textcolor = c;
}

void gfx_setTextBgColor(uint8_t bg) {
        gfx_font.textbgcolor = bg;
}

void gfx_setTextWrap(uint8_t w) {
        gfx_font.wrap = w;
}