General graphics tool

Dependents:   EPD_GDE021A1_demo

Graphic.cpp

Committer:
steeven
Date:
2015-04-15
Revision:
0:404c38e71c68

File content as of revision 0:404c38e71c68:

#include "Graphic.h"

/*
 * Code derived from:
 *  http://developer.mbed.org/users/dreschpe/code/EaEpaper/
 */
Graphic::Graphic(uint8_t *buf, int w, int h, int bits) :
        _buf(buf), _w(w), _h(h), _bits(bits) {
    clear();
    color(0, (1 << bits) - 1);
}

// erase pixel after power up
void Graphic::clear() {
    memset(_buf, 0, _w * _h / (1 << _bits));
    _charX = 0;
    _charY = 0;
}

void Graphic::color(int foreground, int background) {
    int mask = (1 << _bits) - 1;
    _foreColor = foreground & mask;
    _backgroundColor = background & mask;
}

// set one pixel in buffer _newImage
void Graphic::pixel(int x, int y, unsigned int color) {
    unsigned char *v;
    unsigned char bak, pos;
    // first check parameter
    if (x > _w || y > _h || x < 0 || y < 0)
        return;

    color &= ((1 << _bits) - 1); // get valid color
    //memory:y first, then x
    v = &_buf[(x * _h * _bits / 8) + (y * _bits / 8)];

    //pix saved in reverse order in a byte
    pos = 8 - ((y * _bits) % 8) - _bits;

    bak = *v & ~(((1 << _bits) - 1) << pos);
    *v = bak + (color << pos);
}

// print line
void Graphic::line(int x0, int y0, int x1, int y1) {
    int dx = 0, dy = 0;
    int dx_sym = 0, dy_sym = 0;
    int dx_x2 = 0, dy_x2 = 0;
    int di = 0;

    dx = x1 - x0;
    dy = y1 - y0;

    if (dx > 0) {
        dx_sym = 1;
    } else {
        dx_sym = -1;
    }

    if (dy > 0) {
        dy_sym = 1;
    } else {
        dy_sym = -1;
    }

    dx = dx_sym * dx;
    dy = dy_sym * dy;

    dx_x2 = dx * 2;
    dy_x2 = dy * 2;

    if (dx >= dy) {
        di = dy_x2 - dx;
        while (x0 != x1) {

            pixel(x0, y0, _foreColor);
            x0 += dx_sym;
            if (di < 0) {
                di += dy_x2;
            } else {
                di += dy_x2 - dx_x2;
                y0 += dy_sym;
            }
        }
        pixel(x0, y0, _foreColor);
    } else {
        di = dx_x2 - dy;
        while (y0 != y1) {
            pixel(x0, y0, _foreColor);
            y0 += dy_sym;
            if (di < 0) {
                di += dx_x2;
            } else {
                di += dx_x2 - dy_x2;
                x0 += dx_sym;
            }
        }
        pixel(x0, y0, _foreColor);
    }
}

// print rect
void Graphic::rect(int x0, int y0, int x1, int y1) {

    if (x1 > x0)
        line(x0, y0, x1, y0);
    else
        line(x1, y0, x0, y0);

    if (y1 > y0)
        line(x0, y0, x0, y1);
    else
        line(x0, y1, x0, y0);

    if (x1 > x0)
        line(x0, y1, x1, y1);
    else
        line(x1, y1, x0, y1);

    if (y1 > y0)
        line(x1, y0, x1, y1);
    else
        line(x1, y1, x1, y0);
}

// print filled rect
void Graphic::fillrect(int x0, int y0, int x1, int y1) {
    int l, c, i;
    if (x0 > x1) {
        i = x0;
        x0 = x1;
        x1 = i;
    }

    if (y0 > y1) {
        i = y0;
        y0 = y1;
        y1 = i;
    }

    for (l = x0; l <= x1; l++) {
        for (c = y0; c <= y1; c++) {
            pixel(l, c, _foreColor);
        }
    }
}

// print circle
void Graphic::circle(int x0, int y0, int r) {
    int x = -r, y = 0, err = 2 - 2 * r, e2;
    do {
        pixel(x0 - x, y0 + y, _foreColor);
        pixel(x0 + x, y0 + y, _foreColor);
        pixel(x0 + x, y0 - y, _foreColor);
        pixel(x0 - x, y0 - y, _foreColor);
        e2 = err;
        if (e2 <= y) {
            err += ++y * 2 + 1;
            if (-x == y && e2 <= x)
                e2 = 0;
        }
        if (e2 > x)
            err += ++x * 2 + 1;
    } while (x <= 0);

}

// print filled circle
void Graphic::fillcircle(int x0, int y0, int r) {
    int x = -r, y = 0, err = 2 - 2 * r, e2;
    do {
        line(x0 - x, y0 - y, x0 - x, y0 + y);
        line(x0 + x, y0 - y, x0 + x, y0 + y);
        e2 = err;
        if (e2 <= y) {
            err += ++y * 2 + 1;
            if (-x == y && e2 <= x)
                e2 = 0;
        }
        if (e2 > x)
            err += ++x * 2 + 1;
    } while (x <= 0);
}

// set cursor position
void Graphic::locate(int column, int row) {
    _charX = column;
    _charY = row;
}

// calc char columns
int Graphic::columns() {
    int fontW = _font[1];
    return _w / fontW;
}

// calc char rows
int Graphic::rows() {
    int fontH = _font[2];
    return _h / fontH;
}

// print char
void Graphic::putc(int c) {
    int y, x, w, offset; //font
    unsigned char* font;

    int fontBytes = _font[0];
    //int fontW = _font[1];
    int fontH = _font[2];
    int fontColBytes = _font[3];


    if (c == '\n') {    // new line
        _charX = 0;
        _charY = _charY + fontH;
        if (_charY >= _h - fontH) {
            _charY = 0;
        }
        return;
    }
    if ((c < 31) || (c > 127))
        return;   // test char range


    font = &_font[((c - 32) * fontBytes) + 4]; // start of char bitmap
    w = font[0];                          // width of actual char
    if (_charX + w > _w) {
        _charX = 0;
        _charY = _charY + fontH;
        if (_charY >= _h - fontH) {
            _charY = 0;
        }
    }

    font++;
    for (y = 0; y < fontH; y++) {  //  vert line
        for (x = 0; x < w; x++) {   //  horz line
            // vertical then horz in memory
            offset = (x * fontColBytes + y / 8);
            pixel(_charX + x, _charY + y,
                    ((font[offset] >> (y % 8)) & 1) ?
                            _foreColor : _backgroundColor);
        }
    }

    _charX += w;
}

// set actual font
void Graphic::font(const unsigned char* f) {
    _font = (unsigned char *) f;
}

void Graphic::print(const char *str) {
    while (*str) {
        putc(*str);
        str++;
    }
}

void Graphic::print_bm(Bitmap bm, int x, int y) {
    int h, v, b;
    char d;

    for (v = 0; v < bm.ySize; v++) {   // lines
        for (h = 0; h < bm.xSize; h++) { // pixel
            if (h + x > _w)
                break;
            if (v + y > _h)
                break;
            d = bm.data[bm.Byte_in_Line * v + ((h & 0xF8) >> 3)];
            b = 0x80 >> (h & 0x07);
            if ((d & b) == 0) {
                pixel(x + h, y + v, _backgroundColor);
            } else {
                pixel(x + h, y + v, _foreColor);
            }
        }
    }

}