#include "drawing.h" #include "display_spec.h" #include "font.h" extern uint8_t LCD_displayMap[LCD_WIDTH * LCD_HEIGHT / 8]; // This function sets a pixel on displayMap to your preferred // color. 1=Black, 0= white. void LCD_setPixel(int x, int y, enum Color bw) { // First, double check that the coordinate is in range. if ((x >= 0) && (x < LCD_WIDTH) && (y >= 0) && (y < LCD_HEIGHT)) { uint8_t shift = y % 8; if (bw) // If black, set the bit. LCD_displayMap[x + (y / 8) * LCD_WIDTH] |= 1 << shift; else // If white clear the bit. LCD_displayMap[x + (y / 8) * LCD_WIDTH] &= ~(1 << shift); } } // setLine draws a line from x0,y0 to x1,y1 with the set color. // This function was grabbed from the SparkFun ColorLCDShield // library. void LCD_setLine(int x0, int y0, int x1, int y1, enum Color bw) { int dy = y1 - y0; // Difference between y0 and y1 int dx = x1 - x0; // Difference between x0 and x1 int stepx, stepy; if (dy < 0) { dy = -dy; stepy = -1; } else stepy = 1; if (dx < 0) { dx = -dx; stepx = -1; } else stepx = 1; dy <<= 1; // dy is now 2*dy dx <<= 1; // dx is now 2*dx LCD_setPixel(x0, y0, bw); // Draw the first pixel. if (dx > dy) { int fraction = dy - (dx >> 1); while (x0 != x1) { if (fraction >= 0) { y0 += stepy; fraction -= dx; } x0 += stepx; fraction += dy; LCD_setPixel(x0, y0, bw); } } else { int fraction = dx - (dy >> 1); while (y0 != y1) { if (fraction >= 0) { x0 += stepx; fraction -= dy; } y0 += stepy; fraction += dx; LCD_setPixel(x0, y0, bw); } } } // setRect will draw a rectangle from x0,y0 top-left corner to // a x1,y1 bottom-right corner. Can be filled with the fill // parameter, and colored with bw. // This function was grabbed from the SparkFun ColorLCDShield // library. void LCD_setRect(int x0, int y0, int x1, int y1, bool fill, enum Color bw) { // check if the rectangle is to be filled if (fill == 1) { int xDiff; if (x0 > x1) xDiff = x0 - x1; //Find the difference between the x vars else xDiff = x1 - x0; while (xDiff > 0) { LCD_setLine(x0, y0, x0, y1, bw); if (x0 > x1) x0--; else x0++; xDiff--; } } else { // best way to draw an unfilled rectangle is to draw four lines LCD_setLine(x0, y0, x1, y0, bw); LCD_setLine(x0, y1, x1, y1, bw); LCD_setLine(x0, y0, x0, y1, bw); LCD_setLine(x1, y0, x1, y1, bw); } } // setCircle draws a circle centered around x0,y0 with a defined // radius. The circle can be black or white. And have a line // thickness ranging from 1 to the radius of the circle. // This function was grabbed from the SparkFun ColorLCDShield // library. void LCD_setCircle(int x0, int y0, int radius, enum Color bw, int lineThickness) { for (int r = 0; r < lineThickness; r++) { int f = 1 - radius; int ddF_x = 0; int ddF_y = -2 * radius; int x = 0; int y = radius; LCD_setPixel(x0, y0 + radius, bw); LCD_setPixel(x0, y0 - radius, bw); LCD_setPixel(x0 + radius, y0, bw); LCD_setPixel(x0 - radius, y0, bw); while (x < y) { if (f >= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x + 1; LCD_setPixel(x0 + x, y0 + y, bw); LCD_setPixel(x0 - x, y0 + y, bw); LCD_setPixel(x0 + x, y0 - y, bw); LCD_setPixel(x0 - x, y0 - y, bw); LCD_setPixel(x0 + y, y0 + x, bw); LCD_setPixel(x0 - y, y0 + x, bw); LCD_setPixel(x0 + y, y0 - x, bw); LCD_setPixel(x0 - y, y0 - x, bw); } radius--; } } static void LCD_setCharEx(struct Utf8Char character, int x, int y, enum Color color, struct TextStyle style) { const struct FontGraphic *symbol = Font_GetSymbol(character); uint8_t column; // temp byte to store character's column bitmap for (int i = 0; i < 5; i++) // 5 columns (x) per character { column = symbol->columns[i]; for (int j = 0; j < 8; j++) // 8 rows (y) per character { bool bit = column & (1 << j); if (style.size == FONT_NORMAL) { if (bit) {// test bits to set pixels LCD_setPixel(x + i, y + j, color); } else if (style.bg) { LCD_setPixel(x + i, y + j, !color); } } else if (style.size == FONT_DOUBLE) { if (bit) {// test bits to set pixels LCD_setPixel(x + i * 2, y + j * 2, color); LCD_setPixel(x + i * 2 + 1, y + j * 2, color); LCD_setPixel(x + i * 2, y + j * 2 + 1, color); LCD_setPixel(x + i * 2 + 1, y + j * 2 + 1, color); } else if (style.bg) { LCD_setPixel(x + i * 2, y + j * 2, !color); LCD_setPixel(x + i * 2 + 1, y + j * 2, !color); LCD_setPixel(x + i * 2, y + j * 2 + 1, !color); LCD_setPixel(x + i * 2 + 1, y + j * 2 + 1, !color); } } else if (style.size == FONT_BOLD) { if (bit) {// test bits to set pixels LCD_setPixel(x + i, y + j, color); LCD_setPixel(x + i + 1, y + j, color); } else if (style.bg) { LCD_setPixel(x + i, y + j, !color); LCD_setPixel(x + i + 1, y + j, !color); } } } } } // setStr draws a string of characters, calling setChar with // progressive coordinates until it's done. // This function was grabbed from the SparkFun ColorLCDShield // library. void LCD_setStr(const char *dString, int x, int y, enum Color bw) { LCD_setStrEx(dString, x, y, bw, (struct TextStyle) {}); } static const int char_widths[] = { [FONT_NORMAL] = 5, [FONT_DOUBLE] = 10, [FONT_BOLD] = 6 }; static const int char_spacings[] = { [FONT_NORMAL] = 1, [FONT_DOUBLE] = 2, [FONT_BOLD] = 1 }; static const int char_heights[] = { [FONT_NORMAL] = 8, [FONT_DOUBLE] = 16, [FONT_BOLD] = 8 }; // setStr draws a string of characters, calling setChar with // progressive coordinates until it's done. // This function was grabbed from the SparkFun ColorLCDShield // library. AND HEAVILY MODIFIED void LCD_setStrEx(const char *dString, int x, int y, enum Color color, struct TextStyle style) { struct Utf8Char uchar; struct Utf8Iterator iter; Utf8Iterator_Init(&iter, dString); int charw = char_widths[style.size]; int charh = char_heights[style.size]; int spacingx = char_spacings[style.size] + style.spacing_x; int spacingy = style.spacing_y; if (style.align != ALIGN_LEFT) { int line_len = 0; int skip = style.skip; while ((uchar = Utf8Iterator_Next(&iter)).uint) { if (skip > 0) { skip -= 1; continue; } if (uchar.bytes[0] == '\n') { break; } line_len++; } if (style.align == ALIGN_CENTER) { x -= ((charw + spacingx) * line_len) / 2 - spacingx/2; } else { // right x -= ((charw + spacingx) * line_len) - spacingx; } } const int x0 = x; Utf8Iterator_Init(&iter, dString); int limit = style.limit; int skip = style.skip; bool wrap; while ((uchar = Utf8Iterator_Next(&iter)).uint) { if (skip > 0) { skip -= 1; continue; } wrap = uchar.bytes[0] == '\n'; if (!wrap) LCD_setCharEx(uchar, x, y, color, style); if (limit > 0) { limit -= 1; if (limit == 0) return; } if (!wrap) { x += charw; if (style.bg) { for (int i = y; i < y + charh; i++) { for (int j = x; j < x + spacingx; j++) { LCD_setPixel(j, i, !color); } } } } x += spacingx; if (wrap || x > (LCD_WIDTH - charw)) { if (style.nowrap) break; if (style.wrap_to_0) { x = 0; } else { x = x0; } y += charh + spacingy; } // no more characters could be seen if (y >= LCD_HEIGHT) { break; } } } // This function will draw an array over the screen. (For now) the // array must be the same size as the screen, covering the entirety // of the display. void LCD_setBitmap(const uint8_t *bitArray) { for (int i = 0; i < (LCD_WIDTH * LCD_HEIGHT / 8); i++) { LCD_displayMap[i] = bitArray[i]; } } // This function clears the entire display either white (0) or // black (1). // The screen won't actually clear until you call updateDisplay()! void LCD_clearDisplay(enum Color bw) { for (int i = 0; i < (LCD_WIDTH * LCD_HEIGHT / 8); i++) { if (bw) LCD_displayMap[i] = 0xFF; else LCD_displayMap[i] = 0; } } void LCD_invertDisplayData() { /* Indirect, swap bits in displayMap option: */ for (int i = 0; i < (LCD_WIDTH * LCD_HEIGHT / 8); i++) { LCD_displayMap[i] ^= 0xFF; } }