/* Code rewritten from Adafruit Arduino library for the TFT * by Syed Tahmid Mahbub * The TFT itself is Adafruit product 1480 * Included below is the text header from the original Adafruit library * followed by the code */ /* This is the core graphics library for all our displays, providing a common set of graphics primitives (points, lines, circles, etc.). It needs to be paired with a hardware-specific library for each display device we carry (to handle the lower-level functions). Adafruit invests time and resources providing this open source code, please support Adafruit & open-source hardware by purchasing products from Adafruit! Copyright (c) 2013 Adafruit Industries. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "tft_gfx.h" #include "glcdfont.c" #include "tft_master.h" #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) void tft_drawCircle(short x0, short y0, short r, unsigned short color) { /* Draw a circle outline with center (x0,y0) and radius r, with given color * Parameters: * x0: x-coordinate of center of circle. The top-left of the screen * has x-coordinate 0 and increases to the right * y0: y-coordinate of center of circle. The top-left of the screen * has y-coordinate 0 and increases to the bottom * r: radius of circle * color: 16-bit color value for the circle. Note that the circle * isn't filled. So, this is the color of the outline of the circle * Returns: Nothing */ short f = 1 - r; short ddF_x = 1; short ddF_y = -2 * r; short x = 0; short y = r; tft_drawPixel(x0 , y0+r, color); tft_drawPixel(x0 , y0-r, color); tft_drawPixel(x0+r, y0 , color); tft_drawPixel(x0-r, y0 , color); while (x= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x; tft_drawPixel(x0 + x, y0 + y, color); tft_drawPixel(x0 - x, y0 + y, color); tft_drawPixel(x0 + x, y0 - y, color); tft_drawPixel(x0 - x, y0 - y, color); tft_drawPixel(x0 + y, y0 + x, color); tft_drawPixel(x0 - y, y0 + x, color); tft_drawPixel(x0 + y, y0 - x, color); tft_drawPixel(x0 - y, y0 - x, color); } } void tft_drawCircleHelper( short x0, short y0, short r, unsigned char cornername, unsigned short color) { // Helper function for drawing circles and circular objects short f = 1 - r; short ddF_x = 1; short ddF_y = -2 * r; short x = 0; short y = r; while (x= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x; if (cornername & 0x4) { tft_drawPixel(x0 + x, y0 + y, color); tft_drawPixel(x0 + y, y0 + x, color); } if (cornername & 0x2) { tft_drawPixel(x0 + x, y0 - y, color); tft_drawPixel(x0 + y, y0 - x, color); } if (cornername & 0x8) { tft_drawPixel(x0 - y, y0 + x, color); tft_drawPixel(x0 - x, y0 + y, color); } if (cornername & 0x1) { tft_drawPixel(x0 - y, y0 - x, color); tft_drawPixel(x0 - x, y0 - y, color); } } } void tft_fillCircle(short x0, short y0, short r, unsigned short color) { /* Draw a filled circle with center (x0,y0) and radius r, with given color * Parameters: * x0: x-coordinate of center of circle. The top-left of the screen * has x-coordinate 0 and increases to the right * y0: y-coordinate of center of circle. The top-left of the screen * has y-coordinate 0 and increases to the bottom * r: radius of circle * color: 16-bit color value for the circle * Returns: Nothing */ tft_drawFastVLine(x0, y0-r, 2*r+1, color); tft_fillCircleHelper(x0, y0, r, 3, 0, color); } void tft_fillCircleHelper(short x0, short y0, short r, unsigned char cornername, short delta, unsigned short color) { // Helper function for drawing filled circles short f = 1 - r; short ddF_x = 1; short ddF_y = -2 * r; short x = 0; short y = r; while (x= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x; if (cornername & 0x1) { tft_drawFastVLine(x0+x, y0-y, 2*y+1+delta, color); tft_drawFastVLine(x0+y, y0-x, 2*x+1+delta, color); } if (cornername & 0x2) { tft_drawFastVLine(x0-x, y0-y, 2*y+1+delta, color); tft_drawFastVLine(x0-y, y0-x, 2*x+1+delta, color); } } } // Bresenham's algorithm - thx wikpedia void tft_drawLine(short x0, short y0, short x1, short y1, unsigned short color) { /* Draw a straight line from (x0,y0) to (x1,y1) with given color * Parameters: * x0: x-coordinate of starting point of line. The x-coordinate of * the top-left of the screen is 0. It increases to the right. * y0: y-coordinate of starting point of line. The y-coordinate of * the top-left of the screen is 0. It increases to the bottom. * x1: x-coordinate of ending point of line. The x-coordinate of * the top-left of the screen is 0. It increases to the right. * y1: y-coordinate of ending point of line. The y-coordinate of * the top-left of the screen is 0. It increases to the bottom. * color: 16-bit color value for line */ short steep = abs(y1 - y0) > abs(x1 - x0); if (steep) { swap(x0, y0); swap(x1, y1); } if (x0 > x1) { swap(x0, x1); swap(y0, y1); } short dx, dy; dx = x1 - x0; dy = abs(y1 - y0); short err = dx / 2; short ystep; if (y0 < y1) { ystep = 1; } else { ystep = -1; } for (; x0<=x1; x0++) { if (steep) { tft_drawPixel(y0, x0, color); } else { tft_drawPixel(x0, y0, color); } err -= dy; if (err < 0) { y0 += ystep; err += dx; } } } // Draw a rectangle void tft_drawRect(short x, short y, short w, short h, unsigned short color) { /* Draw a rectangle outline with top left vertex (x,y), width w * and height h at given color * Parameters: * x: x-coordinate of top-left vertex. The x-coordinate of * the top-left of the screen is 0. It increases to the right. * y: y-coordinate of top-left vertex. The y-coordinate of * the top-left of the screen is 0. It increases to the bottom. * w: width of the rectangle * h: height of the rectangle * color: 16-bit color of the rectangle outline * Returns: Nothing */ tft_drawFastHLine(x, y, w, color); tft_drawFastHLine(x, y+h-1, w, color); tft_drawFastVLine(x, y, h, color); tft_drawFastVLine(x+w-1, y, h, color); } // Draw a rounded rectangle void tft_drawRoundRect(short x, short y, short w, short h, short r, unsigned short color) { /* Draw a rounded rectangle outline with top left vertex (x,y), width w, * height h and radius of curvature r at given color * Parameters: * x: x-coordinate of top-left vertex. The x-coordinate of * the top-left of the screen is 0. It increases to the right. * y: y-coordinate of top-left vertex. The y-coordinate of * the top-left of the screen is 0. It increases to the bottom. * w: width of the rectangle * h: height of the rectangle * color: 16-bit color of the rectangle outline * Returns: Nothing */ // smarter version tft_drawFastHLine(x+r , y , w-2*r, color); // Top tft_drawFastHLine(x+r , y+h-1, w-2*r, color); // Bottom tft_drawFastVLine(x , y+r , h-2*r, color); // Left tft_drawFastVLine(x+w-1, y+r , h-2*r, color); // Right // draw four corners tft_drawCircleHelper(x+r , y+r , r, 1, color); tft_drawCircleHelper(x+w-r-1, y+r , r, 2, color); tft_drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color); tft_drawCircleHelper(x+r , y+h-r-1, r, 8, color); } // Fill a rounded rectangle void tft_fillRoundRect(short x, short y, short w, short h, short r, unsigned short color) { // smarter version tft_fillRect(x+r, y, w-2*r, h, color); // draw four corners tft_fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color); tft_fillCircleHelper(x+r , y+r, r, 2, h-2*r-1, color); } // Draw a triangle void tft_drawTriangle(short x0, short y0, short x1, short y1, short x2, short y2, unsigned short color) { /* Draw a triangle outline with vertices (x0,y0),(x1,y1),(x2,y2) with given color * Parameters: * x0: x-coordinate of one of the 3 vertices * y0: y-coordinate of one of the 3 vertices * x1: x-coordinate of one of the 3 vertices * y1: y-coordinate of one of the 3 vertices * x2: x-coordinate of one of the 3 vertices * y2: y-coordinate of one of the 3 vertices * color: 16-bit color value for outline * Returns: Nothing */ tft_drawLine(x0, y0, x1, y1, color); tft_drawLine(x1, y1, x2, y2, color); tft_drawLine(x2, y2, x0, y0, color); } // Fill a triangle void tft_fillTriangle ( short x0, short y0, short x1, short y1, short x2, short y2, unsigned short color) { /* Draw a filled triangle with vertices (x0,y0),(x1,y1),(x2,y2) with given color * Parameters: * x0: x-coordinate of one of the 3 vertices * y0: y-coordinate of one of the 3 vertices * x1: x-coordinate of one of the 3 vertices * y1: y-coordinate of one of the 3 vertices * x2: x-coordinate of one of the 3 vertices * y2: y-coordinate of one of the 3 vertices * color: 16-bit color value * Returns: Nothing */ short a, b, y, last; // 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; tft_drawFastHLine(a, y0, b-a+1, color); return; } short dx01 = x1 - x0, dy01 = y1 - y0, dx02 = x2 - x0, dy02 = y2 - y0, dx12 = x2 - x1, dy12 = y2 - y1, sa = 0, sb = 0; // 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); tft_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); tft_drawFastHLine(a, y, b-a+1, color); } } void tft_drawBitmap(short x, short y, const unsigned char *bitmap, short w, short h, unsigned short color) { short i, j, byteWidth = (w + 7) / 8; for(j=0; j> (i & 7))) { tft_drawPixel(x+i, y+j, color); } } } } void tft_write(unsigned char c){ if (c == '\n') { cursor_y += textsize*8; cursor_x = 0; } else if (c == '\r') { // skip em } else if (c == '\t'){ int new_x = cursor_x + tabspace; if (new_x < _width){ cursor_x = new_x; } } else { tft_drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize); cursor_x += textsize*6; if (wrap && (cursor_x > (_width - textsize*6))) { cursor_y += textsize*8; cursor_x = 0; } } } inline void tft_writeString(char* str){ /* Print text onto screen * Call tft_setCursor(), tft_setTextColor(), tft_setTextSize() * as necessary before printing */ while (*str){ tft_write(*str++); } } // Draw a character void tft_drawChar(short x, short y, unsigned char c, unsigned short color, unsigned short bg, unsigned char size) { char i, j; if((x >= _width) || // Clip right (y >= _height) || // Clip bottom ((x + 6 * size - 1) < 0) || // Clip left ((y + 8 * size - 1) < 0)) // Clip top return; for (i=0; i<6; i++ ) { unsigned char line; if (i == 5) line = 0x0; else line = pgm_read_byte(font+(c*5)+i); for ( j = 0; j<8; j++) { if (line & 0x1) { if (size == 1) // default size tft_drawPixel(x+i, y+j, color); else { // big size tft_fillRect(x+(i*size), y+(j*size), size, size, color); } } else if (bg != color) { if (size == 1) // default size tft_drawPixel(x+i, y+j, bg); else { // big size tft_fillRect(x+i*size, y+j*size, size, size, bg); } } line >>= 1; } } } inline void tft_setCursor(short x, short y) { /* Set cursor for text to be printed * Parameters: * x = x-coordinate of top-left of text starting * y = y-coordinate of top-left of text starting * Returns: Nothing */ cursor_x = x; cursor_y = y; } inline void tft_setTextSize(unsigned char s) { /*Set size of text to be displayed * Parameters: * s = text size (1 being smallest) * Returns: nothing */ textsize = (s > 0) ? s : 1; } inline void tft_setTextColor(unsigned short c) { // For 'transparent' background, we'll set the bg // to the same as fg instead of using a flag textcolor = textbgcolor = c; } inline void tft_setTextColor2(unsigned short c, unsigned short b) { /* Set color of text to be displayed * Parameters: * c = 16-bit color of text * b = 16-bit color of text background */ textcolor = c; textbgcolor = b; } inline void tft_setTextWrap(char w) { wrap = w; } inline unsigned char tft_getRotation(void) { /* Returns current roation of screen * 0 = no rotation (0 degree rotation) * 1 = rotate 90 degree clockwise * 2 = rotate 180 degree * 3 = rotate 90 degree anticlockwise */ return rotation; } void tft_gfx_setRotation(unsigned char x) { /* Set display rotation in 90 degree steps * Parameters: * x: dictate direction of rotation * 0 = no rotation (0 degree rotation) * 1 = rotate 90 degree clockwise * 2 = rotate 180 degree * 3 = rotate 90 degree anticlockwise * Returns: Nothing */ rotation = (x & 3); switch(rotation) { case 0: case 2: _width = ILI9341_TFTWIDTH; _height = ILI9341_TFTHEIGHT; break; case 1: case 3: _width = ILI9341_TFTHEIGHT;; _height = ILI9341_TFTWIDTH; break; } } // Return the size of the display (per current rotation) inline short tft_width(void) { return _width; } inline short tft_height(void) { return _height; }