Last active
November 12, 2017 13:55
-
-
Save vishnumaiea/47c9fe7f820c723de6a0d2c6872d1db2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//========================================================================// | |
// // | |
// ILI9481 3.2" 320 x 480 TFT LCD Driver for ESP32 // | |
// // | |
// Author : Vishnu M Aiea // | |
// GitHub : https://github.com/vishnumaiea // | |
// License : GNU GPL v3 // | |
// Date Created : IST 04:07:07 PM, 30-10-2017, Monday // | |
// Last Modified : 07:24:42 PM, 12-11-2017, Sunday // | |
// File Version : 4 // | |
// // | |
//========================================================================// | |
#include <pgmspace.h> | |
// #include <esp_clk.h> | |
#define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; } //swaps two 16 bit values | |
//========================================================================// | |
//font specific declarations | |
// #include "Montserrat_Medium21x20.h" | |
#include "Poppins_Medium34x36.h" | |
class fontClass { | |
public: | |
const char * fontArray; | |
int fontWidth; //width of each char (don't worry; char widths are still variable) | |
int fontHeight; //font height | |
int charByteLength; //count of bytes for each char | |
int verticalByteCount; //no. of vertical bytes needed for a char | |
char startChar; //first char in font | |
char endChar; //last char in font | |
int charCount; //total char count in font | |
fontClass (const char * a, int w, int h, int c, int v, char s, char e, int n) { | |
fontArray = a; | |
fontWidth = w; | |
fontHeight = h; | |
charByteLength = c; | |
verticalByteCount = v; | |
startChar = s; | |
endChar = e; | |
charCount = n; | |
} | |
}; | |
// fontClass * Montserrat_Medium21x20; //create a pointer so that can be initialized later | |
fontClass * Poppins_Medium34x36; | |
// Montserrat_Medium21x20.fontArray = someArray; | |
// Montserrat_Medium21x20.fontWidth = 21; | |
// Montserrat_Medium21x20.fontHeight = 20; | |
// Montserrat_Medium21x20.charByteLength = 64; | |
// Montserrat_Medium21x20.verticalByteCount = 3; | |
// Montserrat_Medium21x20.startChar = 33; | |
// Montserrat_Medium21x20.endChar = 126; | |
// Montserrat_Medium21x20.charCount = 93; | |
//========================================================================// | |
//define the pins for 8-bit parallel drive | |
#define CS_PIN 26 | |
#define RST_PIN 12 | |
#define DC_PIN 14 | |
#define WR_PIN 27 | |
#define PD0 15 //parallel data pins | |
#define PD1 2 | |
#define PD2 0 | |
#define PD3 4 | |
#define PD4 16 | |
#define PD5 17 | |
#define PD6 21 | |
#define PD7 22 | |
//========================================================================// | |
//display specific parameters | |
static const int Width = 320; //constants | |
static const int Height = 480; | |
int _width = Width; //becasue we can change these later if needed | |
int _height = Height; //eg in setRotation() | |
//========================================================================// | |
//function declarations | |
void writeData (uint8_t); | |
void writeCommand (uint8_t); | |
void initializeDisplay (void); | |
void startDisplay (void); | |
void writeData16 (uint16_t); | |
void writeData8 (uint8_t); | |
void displayOn (void); | |
void displayOff (void); | |
void setAddrWindow (int, int, int, int); | |
void drawPixel (int, int, uint16_t); | |
void fillScreen (uint16_t); | |
void fillRectangle (int, int, int, int, uint16_t); | |
void drawHorizontalLine (int, int, int, uint16_t); | |
void drawVerticalLine (int, int, int, uint16_t); | |
void setRotation (int); | |
void invertDisplay (bool); | |
void openWindow (int, int, int, int); | |
void windowData (uint16_t); | |
void windowData (uint16_t*, int); | |
//========================================================================// | |
//setup function runs once | |
void setup() { | |
//font initializations | |
// Montserrat_Medium21x20 = new fontClass ( Montserrat_Medium21x20_fontArray, | |
// Montserrat_Medium21x20_fontWidth, | |
// Montserrat_Medium21x20_fontHeight, | |
// Montserrat_Medium21x20_charByteLength, | |
// Montserrat_Medium21x20_verticalByteCount, | |
// Montserrat_Medium21x20_startChar, | |
// Montserrat_Medium21x20_endChar, | |
// Montserrat_Medium21x20_charCount ); | |
Poppins_Medium34x36 = new fontClass ( Poppins_Medium34x36_fontArray, | |
Poppins_Medium34x36_fontWidth, | |
Poppins_Medium34x36_fontHeight, | |
Poppins_Medium34x36_charByteLength, | |
Poppins_Medium34x36_verticalByteCount, | |
Poppins_Medium34x36_startChar, | |
Poppins_Medium34x36_endChar, | |
Poppins_Medium34x36_charCount ); | |
Serial.begin(115200); | |
Serial.print("CPU Clock = "); | |
Serial.println(ESP.getCpuFreqMHz()); | |
Serial.println("Initializing..."); | |
Serial.println(); | |
pinMode(CS_PIN, OUTPUT); //set all pins as outputs | |
pinMode(RST_PIN, OUTPUT); | |
pinMode(DC_PIN, OUTPUT); | |
pinMode(WR_PIN, OUTPUT); | |
pinMode(PD0, OUTPUT); | |
pinMode(PD1, OUTPUT); | |
pinMode(PD2, OUTPUT); | |
pinMode(PD3, OUTPUT); | |
pinMode(PD4, OUTPUT); | |
pinMode(PD5, OUTPUT); | |
pinMode(PD6, OUTPUT); | |
pinMode(PD7, OUTPUT); | |
initializeDisplay(); | |
setRotation(1); | |
delay(1); | |
setAddrWindow(0, 0, _width, _height); | |
fillScreen(65535); | |
} | |
//========================================================================// | |
//infinite loop | |
int color = 0; | |
void loop() { | |
//drawHorizontalLine(50, 300, 470, 10); | |
//drawVerticalLine(50, 50, 350, 10); | |
// drawLine(10, 20, 300, 255, 21); //x0, y0, x1, y1, color | |
// drawCircle(200, 200, 100, 20); | |
// fillCircle(200, 200, 100, 5000); | |
// drawRoundRectangle(100, 100, 100, 100, 10, 500); | |
// fillRoundRectangle(100, 100, 100, 100, 10, 6500); | |
// fillRectangle(100, 100, 100, 100, 4000); | |
// drawRectangle(100, 100, 100, 100, 200); | |
// delay(200); | |
// Serial.println("Working.."); | |
// Serial.print("CPU Clock = "); | |
// Serial.println(ESP.getCpuFreqMHz()); | |
// if(color >= 65535) color = 0; | |
// | |
// //displayOff(); | |
// setAddrWindow(0, 0, _width, _height); | |
// for(int i=0; i<320; i++) { | |
// for(int j=0; j<480; j++) { | |
// writeData16(color); | |
// } | |
// } | |
// color++; | |
// delay(1); | |
// fillScreen(65535); | |
// delay(1000); | |
// fillScreen(0); | |
// delay(1000); | |
// for(int i=33; i<127; i++) { | |
// drawChar(100, 100, i, 0, 65535, Poppins_Medium34x36); | |
// delay(500); | |
// fillScreen(65535); | |
// } | |
printText("VISHNU M AIEA", 100, 100, 0, 65535, Poppins_Medium34x36); | |
delay(10); | |
// String S = "VISHNU"; | |
// char stringBuffer[S.length()+1]; | |
// Serial.println(S.length()+1); | |
// S.toCharArray(stringBuffer, S.length()+1); | |
// Serial.println(stringBuffer); | |
} | |
//========================================================================// | |
//initializes the display with proper reset sequence | |
void initializeDisplay() { | |
digitalWrite(DC_PIN, HIGH); //DC high | |
digitalWrite(CS_PIN, HIGH); //CS high | |
digitalWrite(WR_PIN, HIGH); //WR high | |
digitalWrite(RST_PIN, HIGH); //RST high | |
delay(100); | |
digitalWrite(RST_PIN, LOW); //RST low | |
delay(100); | |
digitalWrite(RST_PIN, HIGH); //RST high | |
delay(100); | |
digitalWrite(CS_PIN, LOW); //CS low | |
startDisplay(); | |
Serial.println("LCD Initialized."); | |
} | |
//========================================================================// | |
//starts the display with required configurations | |
void startDisplay() { | |
writeCommand(0x11); //exit sleep mode | |
delay(80); | |
writeCommand(0xD0); //power setting | |
writeData8(0x07); | |
writeData8(0x42); | |
writeData8(0x18); | |
writeCommand(0xD1); //VCOM control | |
writeData8(0x00); | |
writeData8(0x07); | |
writeData8(0x10); | |
writeCommand(0xD2); //power setting for normal mode | |
writeData8(0x01); | |
writeData8(0x02); //Fosc setting | |
writeCommand(0xC0); //panel driving setting - 5 parameters | |
writeData8(0x10); //REV=1, SM=0, GS=0 - grayscale inversion enabled : will invert colors | |
//writeData8(0x00); //REV=0, SM=0, GS=0 - no color inversion | |
writeData8(0x3B); //NL[5] - max lines | |
writeData8(0x00); //SCN - scanning start position | |
writeData8(0x02); //NDL (non-display area o/p level), PTS[3] | |
//writeData8(0x11); //PTG=1 (interval scan), ISC[3]=0001 (3 frames) | |
// writeData8(0x1F); //PTG=1 (interval scan), ISC[3]=1111 (31 frames) | |
writeData8(0x01); //PTG=0 (normal scan), ISC[3]=0002 (3 frames) | |
writeCommand(0xC5); //frame rate and inversion control - 1 parameter | |
//writeData8(0x03); //72FPS (default) - this had backlight flickering | |
writeData8(0x00); //125 FPS (max) - this has no flickering | |
writeCommand(0xB3); //frame memeory access and interface setting | |
writeData8(0x0); //extra data is ignored | |
writeData8(0x0); //all defaults | |
writeData8(0x0); | |
writeData8(0x0); | |
writeCommand(0x35); //tearing compensation | |
writeData8(0x0); | |
writeCommand(0xC1); //display timing for normal mode | |
writeData8(0x10); //BC=0 (frame inversion waveform) | |
writeData8(0x10); //line period is 16 clocks | |
writeData8(0x22); //front and back porch lines = 2 | |
writeCommand(0xC8); //gamma setting | |
writeData8(0x00); | |
writeData8(0x32); | |
writeData8(0x36); | |
writeData8(0x45); | |
writeData8(0x06); | |
writeData8(0x16); | |
writeData8(0x37); | |
writeData8(0x75); | |
writeData8(0x77); | |
writeData8(0x54); | |
writeData8(0x0C); | |
writeData8(0x00); | |
writeCommand(0x36); //set address mode - 1 parameter | |
writeData8(0x0A); //BGR, horizontal flip | |
writeCommand(0x13); //eneter normal mode - no param | |
writeCommand(0x3A); //set pixel format - 1 parameter | |
writeData8(0x55); //16-bit per pixel | |
//writeData(0x66); //18-bit per pixel | |
setAddrWindow(0, 0, _width, _height); | |
//writeCommand(0x2A); //set column address | |
//writeData8(0x00); | |
//writeData8(0x00); | |
//writeData8(0x01); | |
//writeData8(0x3F); | |
//writeCommand(0x2B); //set page address | |
//writeData8(0x00); | |
//writeData8(0x00); | |
//writeData8(0x01); | |
//writeData8(0xDF); | |
delay(120); | |
writeCommand(0x29); //set display on | |
} | |
//========================================================================// | |
//writes 8 bit data | |
void writeData (uint8_t inputData) { | |
digitalWrite(CS_PIN, LOW); //CS low | |
digitalWrite(RST_PIN, HIGH); //RST high | |
digitalWrite(DC_PIN, HIGH); //DC high | |
digitalWrite(WR_PIN, HIGH); //WR high | |
writeToPins(inputData); | |
} | |
//========================================================================// | |
//writes 8 bit command | |
void writeCommand (uint8_t inputCommand) { | |
digitalWrite(CS_PIN, LOW); //CS low | |
digitalWrite(RST_PIN, HIGH); //RST high | |
digitalWrite(DC_PIN, LOW); //DC low | |
digitalWrite(WR_PIN, HIGH); //WR high | |
writeToPins(inputCommand); | |
digitalWrite(DC_PIN, HIGH); //high | |
} | |
//========================================================================// | |
//writes 16 bit data to the 8-bit bus | |
void writeData16 (uint16_t inputData) { | |
digitalWrite(DC_PIN, HIGH); //DC high | |
uint8_t highByte = (uint8_t) ((unsigned int)(inputData >> 8) & 0x00FF); //write the high byte (big endian) | |
writeToPins(highByte); | |
uint8_t lowByte = (uint8_t) inputData & 0x00FF; //writes the low byte | |
writeToPins(lowByte); | |
} | |
//========================================================================// | |
//writes 8-bit data to 8-bit bus | |
void writeData8 (uint8_t inputData) { | |
digitalWrite(DC_PIN, HIGH); //DC high | |
writeToPins(inputData); | |
} | |
//========================================================================// | |
//writes 8-bit data to individual pins | |
//LSB is ANDed with 1, and writes HIGH is the ouput is 1, LOW otherwise | |
//then the data is shifted right to do this for all 8 bits | |
void writeToPins (uint8_t inputData) { | |
digitalWrite (PD0, (((inputData & 0x01) == 1) ? HIGH : LOW)); //no need to shift here | |
digitalWrite (PD1, ((((unsigned int)(inputData >> 1) & 0x01) == 1) ? HIGH : LOW)); //AND the 2nd bit | |
digitalWrite (PD2, ((((unsigned int)(inputData >> 2) & 0x01) == 1) ? HIGH : LOW)); | |
digitalWrite (PD3, ((((unsigned int)(inputData >> 3) & 0x01) == 1) ? HIGH : LOW)); | |
digitalWrite (PD4, ((((unsigned int)(inputData >> 4) & 0x01) == 1) ? HIGH : LOW)); | |
digitalWrite (PD5, ((((unsigned int)(inputData >> 5) & 0x01) == 1) ? HIGH : LOW)); | |
digitalWrite (PD6, ((((unsigned int)(inputData >> 6) & 0x01) == 1) ? HIGH : LOW)); | |
digitalWrite (PD7, ((((unsigned int)(inputData >> 7) & 0x01) == 1) ? HIGH : LOW)); | |
digitalWrite (WR_PIN, LOW); //WR low | |
digitalWrite (WR_PIN, HIGH); //WR high | |
} | |
//========================================================================// | |
void displayOn () { | |
writeCommand (0x29); //set display on | |
} | |
//========================================================================// | |
void displayOff () { | |
writeCommand (0x28); //set display off | |
} | |
//========================================================================// | |
//sets the number of pixels (or a rectangular window) data to be written to | |
void setAddrWindow(int x0, int y0, int x1, int y1) { | |
x1 = (x1 >= _width) ? _width -1 : x1; | |
y1 = (y1 >= _height) ? _height -1 : y1; | |
writeCommand(0x2A); //set col address - 4 param | |
writeData16(x0); | |
writeData16(x1); | |
writeCommand(0x2B); //set page address - 4 param | |
writeData16(y0); | |
writeData16(y1); | |
writeCommand(0x2C); //write memory start | |
//writeCommand(0x3C); //write memory continue | |
} | |
//========================================================================// | |
//sets a single pixel to a color | |
void drawPixel(int x, int y, uint16_t color) { | |
if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return; | |
setAddrWindow(x,y,x,y); | |
writeData16(color); | |
} | |
//========================================================================// | |
//fills the entire screen with a color | |
void fillScreen(uint16_t color) { | |
//fillRectangle(0, 0, _width, _height, color); | |
setAddrWindow(0, 0, _width, _height); | |
for(int i=0; i<_height; i++) { | |
for(int j=0; j<_width; j++) { | |
writeData16(color); | |
} | |
} | |
} | |
//========================================================================// | |
//fast drawing of horizontal line | |
void drawHorizontalLine(int x, int y, int w, uint16_t color) { | |
// Rudimentary clipping | |
if((x >= _width) || (y >= _height)) | |
return; | |
if((x+w-1) >= _width) | |
w = _width-x; | |
setAddrWindow(x, y, x+w-1, y); | |
while (w--) { | |
writeData16(color); | |
} | |
} | |
//========================================================================// | |
//fast drawing of vertical line | |
void drawVerticalLine(int x, int y, int h, uint16_t color) { | |
if((x >= _width) || (y >= _height)) | |
return; | |
if((y+h-1) >= _height) | |
h = _height-y; | |
setAddrWindow(x, y, x, y+h-1); | |
while (h--) { | |
writeData16(color); | |
} | |
} | |
//========================================================================// | |
void setRotation(int m) { | |
writeCommand (0x36); //set address mode | |
int rotation = m % 4; // can't be higher than 3 | |
switch (rotation) { | |
case 0: | |
writeData8(0x0A); | |
_width = Width; | |
_height = Height; | |
break; | |
case 1: | |
writeData8(0x28); | |
_width = Height; | |
_height = Width; | |
break; | |
case 2: | |
writeData8(0x09); | |
_width = Width; | |
_height = Height; | |
break; | |
case 3: | |
writeData8(0x2B); | |
_width = Height; | |
_height = Width; | |
break; | |
} | |
} | |
//========================================================================// | |
void invertDisplay(boolean i) { | |
writeCommand(i ? 0x21 : 0x20); | |
} | |
//========================================================================// | |
void openWindow(int x0, int y0, int x1, int y1) { | |
setAddrWindow(x0, y0, x0 + x1 - 1, y0 + y1 - 1); | |
} | |
//========================================================================// | |
//writes a single 16b data to the data lines | |
void windowData(uint16_t c) { | |
writeData16(c); | |
} | |
//========================================================================// | |
//writes an array of data to the data lines | |
void windowData(uint16_t *c, int len) { | |
for (uint32_t i = 0; i < len; i++) { | |
writeData16(c[i]); | |
} | |
} | |
//========================================================================// | |
//bressenham's line algorithm | |
void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color) { | |
int16_t steep = abs(y1 - y0) > abs(x1 - x0); | |
if (steep) { | |
_swap_int16_t(x0, y0); | |
_swap_int16_t(x1, y1); | |
} | |
if (x0 > x1) { | |
_swap_int16_t(x0, x1); | |
_swap_int16_t(y0, y1); | |
} | |
int16_t dx, dy; | |
dx = x1 - x0; | |
dy = abs(y1 - y0); | |
int16_t err = dx / 2; | |
int16_t ystep; | |
if (y0 < y1) { | |
ystep = 1; | |
} else { | |
ystep = -1; | |
} | |
for (; x0<=x1; x0++) { | |
if (steep) { | |
drawPixel(y0, x0, color); | |
} else { | |
drawPixel(x0, y0, color); | |
} | |
err -= dy; | |
if (err < 0) { | |
y0 += ystep; | |
err += dx; | |
} | |
} | |
} | |
//========================================================================// | |
// Draw a rectangle | |
void drawRectangle(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { | |
drawHorizontalLine(x, y, w, color); | |
drawHorizontalLine(x, y+h-1, w, color); | |
drawVerticalLine(x, y, h, color); | |
drawVerticalLine(x+w-1, y, h, color); | |
} | |
//========================================================================// | |
//fills a rectanglar area os display with a color | |
void fillRectangle(int x, int y, int w, int h, uint16_t color) { //fillRectangle(0, 0, 480, 320, 6500); | |
if((x >= _width) || (y >= _height)) | |
return; | |
if((x + w - 1) >= _width) | |
w = _width - x; | |
if((y + h - 1) >= _height) | |
h = _height - y; | |
setAddrWindow(x, y, x+w-1, y+h-1); | |
for(y=h*2; y>0; y--) { | |
for(x=w; x>0; x--) { | |
writeData16(color); | |
} | |
} | |
} | |
//========================================================================// | |
// Draw a circle outline | |
void drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color) { | |
int16_t f = 1 - r; | |
int16_t ddF_x = 1; | |
int16_t ddF_y = -2 * r; | |
int16_t x = 0; | |
int16_t y = r; | |
drawPixel(x0 , y0+r, color); | |
drawPixel(x0 , y0-r, color); | |
drawPixel(x0+r, y0 , color); | |
drawPixel(x0-r, y0 , color); | |
while (x<y) { | |
if (f >= 0) { | |
y--; | |
ddF_y += 2; | |
f += ddF_y; | |
} | |
x++; | |
ddF_x += 2; | |
f += ddF_x; | |
drawPixel(x0 + x, y0 + y, color); | |
drawPixel(x0 - x, y0 + y, color); | |
drawPixel(x0 + x, y0 - y, color); | |
drawPixel(x0 - x, y0 - y, color); | |
drawPixel(x0 + y, y0 + x, color); | |
drawPixel(x0 - y, y0 + x, color); | |
drawPixel(x0 + y, y0 - x, color); | |
drawPixel(x0 - y, y0 - x, color); | |
} | |
} | |
//========================================================================// | |
void drawCircleHelper( int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint16_t color) { | |
int16_t f = 1 - r; | |
int16_t ddF_x = 1; | |
int16_t ddF_y = -2 * r; | |
int16_t x = 0; | |
int16_t y = r; | |
while (x<y) { | |
if (f >= 0) { | |
y--; | |
ddF_y += 2; | |
f += ddF_y; | |
} | |
x++; | |
ddF_x += 2; | |
f += ddF_x; | |
if (cornername & 0x4) { | |
drawPixel(x0 + x, y0 + y, color); | |
drawPixel(x0 + y, y0 + x, color); | |
} | |
if (cornername & 0x2) { | |
drawPixel(x0 + x, y0 - y, color); | |
drawPixel(x0 + y, y0 - x, color); | |
} | |
if (cornername & 0x8) { | |
drawPixel(x0 - y, y0 + x, color); | |
drawPixel(x0 - x, y0 + y, color); | |
} | |
if (cornername & 0x1) { | |
drawPixel(x0 - y, y0 - x, color); | |
drawPixel(x0 - x, y0 - y, color); | |
} | |
} | |
} | |
//========================================================================// | |
void fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color) { | |
drawVerticalLine(x0, y0-r, 2*r+1, color); | |
fillCircleHelper(x0, y0, r, 3, 0, color); | |
} | |
//========================================================================// | |
// Used to do circles and roundrects | |
void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, int16_t delta, uint16_t color) { | |
int16_t f = 1 - r; | |
int16_t ddF_x = 1; | |
int16_t ddF_y = -2 * r; | |
int16_t x = 0; | |
int16_t y = r; | |
while (x<y) { | |
if (f >= 0) { | |
y--; | |
ddF_y += 2; | |
f += ddF_y; | |
} | |
x++; | |
ddF_x += 2; | |
f += ddF_x; | |
if (cornername & 0x1) { | |
drawVerticalLine(x0+x, y0-y, 2*y+1+delta, color); | |
drawVerticalLine(x0+y, y0-x, 2*x+1+delta, color); | |
} | |
if (cornername & 0x2) { | |
drawVerticalLine(x0-x, y0-y, 2*y+1+delta, color); | |
drawVerticalLine(x0-y, y0-x, 2*x+1+delta, color); | |
} | |
} | |
} | |
//========================================================================// | |
// Draw a rounded rectangle | |
void drawRoundRectangle(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color) { | |
// smarter version | |
drawHorizontalLine(x+r , y , w-2*r, color); // Top | |
drawHorizontalLine(x+r , y+h-1, w-2*r, color); // Bottom | |
drawVerticalLine(x , y+r , h-2*r, color); // Left | |
drawVerticalLine(x+w-1, y+r , h-2*r, color); // Right | |
// draw four corners | |
drawCircleHelper(x+r , y+r , r, 1, color); | |
drawCircleHelper(x+w-r-1, y+r , r, 2, color); | |
drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color); | |
drawCircleHelper(x+r , y+h-r-1, r, 8, color); | |
} | |
//========================================================================// | |
// Fill a rounded rectangle | |
void fillRoundRectangle(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color) { | |
// smarter version | |
fillRectangle(x+r, y, w-2*r, h, color); | |
// draw four corners | |
fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color); | |
fillCircleHelper(x+r , y+r, r, 2, h-2*r-1, color); | |
} | |
//========================================================================// | |
// Draw a triangle | |
void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) { | |
drawLine(x0, y0, x1, y1, color); | |
drawLine(x1, y1, x2, y2, color); | |
drawLine(x2, y2, x0, y0, color); | |
} | |
//========================================================================// | |
// Fill a triangle | |
void fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) { | |
int16_t a, b, y, last; | |
// Sort coordinates by Y order (y2 >= y1 >= y0) | |
if (y0 > y1) { | |
_swap_int16_t(y0, y1); _swap_int16_t(x0, x1); | |
} | |
if (y1 > y2) { | |
_swap_int16_t(y2, y1); _swap_int16_t(x2, x1); | |
} | |
if (y0 > y1) { | |
_swap_int16_t(y0, y1); _swap_int16_t(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; | |
drawHorizontalLine(a, y0, b-a+1, color); | |
return; | |
} | |
int16_t | |
dx01 = x1 - x0, | |
dy01 = y1 - y0, | |
dx02 = x2 - x0, | |
dy02 = y2 - y0, | |
dx12 = x2 - x1, | |
dy12 = y2 - y1; | |
int32_t | |
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_int16_t(a,b); | |
drawHorizontalLine(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_int16_t(a,b); | |
drawHorizontalLine(a, y, b-a+1, color); | |
} | |
} | |
//========================================================================// | |
//draws a single char to the display | |
void drawChar(char letter, int16_t x, int16_t y, uint16_t color, uint16_t bg, fontClass* selectedFont) { | |
// for(int i=0; i < selectedFont->fontHeight; i++) { | |
// drawHorizontalLine(x, y+i, selectedFont->fontWidth, bg); //clear the bg with bg color | |
// } | |
Serial.print("Drawing char : "); | |
Serial.println(letter); | |
char verticalBytes [selectedFont->verticalByteCount]; //for vertical bytes | |
for(int i=0; i < (selectedFont->fontArray[((letter - selectedFont->startChar) * selectedFont->charByteLength)]); i++) { //finds start of each set of vertical bytes | |
for(int k=1; k <= selectedFont->verticalByteCount; k++) { | |
verticalBytes [k-1] = selectedFont->fontArray[((letter - selectedFont->startChar) * selectedFont->charByteLength) + k + (i * selectedFont->verticalByteCount)]; //copy the set of vertical bytes | |
} | |
for(int j=0; j < selectedFont->verticalByteCount; j++) { //iterates though each set of vertical bytes | |
if(verticalBytes[j] != 0) { //don't display if a byte is zero | |
for(int m=0; m < 8; m++) { //iterates though each pixel of a byte | |
if((((unsigned int)(verticalBytes[j] >> m)) & 0x1) == 0x1) //check if a bit is 1 | |
drawPixel(x+i, y + m+ (8*j), color); //if a bit is 1, then draw pixel with color | |
else drawPixel(x+i, y + m+ (8*j), bg); //draw pixel with bg if otherwise | |
// delay(100); | |
} | |
} | |
} | |
} | |
} | |
//========================================================================// | |
void printText(String S, int16_t x, int16_t y, uint16_t color, uint16_t bg, fontClass* selectedFont) { | |
char stringBuffer[S.length()+1]; | |
S.toCharArray(stringBuffer, S.length()+1); //create a char array | |
for(int i=0; i < S.length(); i++) { | |
if(((stringBuffer[i] < selectedFont->startChar) || (stringBuffer[i] > selectedFont->endChar)) && (stringBuffer[i] != 32)) { //check for char validity | |
Serial.print("Illegal character found : "); | |
Serial.print((int)stringBuffer[i]); | |
Serial.print(" at "); | |
Serial.println(i); | |
Serial.println("String Length : " + S.length()); | |
return; | |
} | |
} | |
int cumulatedLength = 0; | |
for(int i=0; i < S.length(); i++) { | |
if(i==0) { | |
if(stringBuffer[i] == 32) { //if the char is a space | |
cumulatedLength += 10; //width for space char | |
Serial.println("Writing space.."); | |
} | |
else { | |
Serial.print("Writing first char : "); | |
Serial.println(stringBuffer[i]); | |
drawChar(stringBuffer[i], x, y, color, bg, selectedFont); | |
cumulatedLength += selectedFont->fontArray[((stringBuffer[i] - selectedFont->startChar) * selectedFont->charByteLength)] + 2; | |
} | |
} | |
else { | |
if(stringBuffer[i] == 32) { //if the char is a space | |
Serial.println("Writing space.."); | |
cumulatedLength += 10; //width for space char | |
} | |
else { | |
Serial.print("Writing char : "); | |
Serial.println(stringBuffer[i]); | |
drawChar(stringBuffer[i], (x + cumulatedLength), y, color, bg, selectedFont); | |
cumulatedLength += selectedFont->fontArray[((stringBuffer[i] - selectedFont->startChar) * selectedFont->charByteLength)] + 2; | |
} | |
} | |
} | |
} | |
//========================================================================// |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Wow