|
| 1 | +// Sketch to demonstrate smooth (anti-aliased) graphics functions: |
| 2 | +// Smooth graphics result in less pixel resolution jaggedness. |
| 3 | + |
| 4 | +#include <TFT_eSPI.h> |
| 5 | +#include "SerialUSB.h" |
| 6 | + |
| 7 | +TFT_eSPI tft; // Invoke library, pins defined in User_Setup.h |
| 8 | + |
| 9 | + // Small sprite for spot demo |
| 10 | +TFT_eSprite spr = TFT_eSprite(&tft); |
| 11 | + |
| 12 | +// ========================================================================= |
| 13 | +// Setup |
| 14 | +// ========================================================================= |
| 15 | +void setup() { |
| 16 | + Serial.begin(115200); |
| 17 | + Serial.println("Booting..."); |
| 18 | + |
| 19 | + // Initialise the screen |
| 20 | + tft.init(); |
| 21 | + |
| 22 | + // Ideally set orientation for good viewing angle range because |
| 23 | + // the anti-aliasing effectiveness varies with screen viewing angle |
| 24 | + tft.setRotation(0); |
| 25 | + |
| 26 | + tft.fillScreen(BLACK); |
| 27 | +} |
| 28 | + |
| 29 | +// ========================================================================= |
| 30 | +// Get coordinates of two ends of a line from r1 to r2, pivot at x,y, angle a |
| 31 | +// ========================================================================= |
| 32 | +// Coordinates are returned to caller via the xp and yp pointers |
| 33 | +#define DEG2RAD 0.0174532925 |
| 34 | +void getCoord(int16_t x, int16_t y, float *xp1, float *yp1, float *xp2, float *yp2, int16_t r1, int16_t r2, float a) |
| 35 | +{ |
| 36 | + float sx = cos( (a - 90) * DEG2RAD); |
| 37 | + float sy = sin( (a - 90) * DEG2RAD); |
| 38 | + *xp1 = sx * r1 + x; |
| 39 | + *yp1 = sy * r1 + y; |
| 40 | + *xp2 = sx * r2 + x; |
| 41 | + *yp2 = sy * r2 + y; |
| 42 | +} |
| 43 | + |
| 44 | +// ========================================================================= |
| 45 | +// Return a 16-bit rainbow colour |
| 46 | +// ========================================================================= |
| 47 | +unsigned int rainbow(byte value) |
| 48 | +{ |
| 49 | + // Value is expected to be in range 0-127 |
| 50 | + // The value is converted to a spectrum colour from 0 = blue through to 127 = red |
| 51 | + |
| 52 | + byte red = 0; // Red is the top 5 bits of a 16-bit colour value |
| 53 | + byte green = 0;// Green is the middle 6 bits |
| 54 | + byte blue = 0; // Blue is the bottom 5 bits |
| 55 | + |
| 56 | + byte quadrant = value / 32; |
| 57 | + |
| 58 | + if (quadrant == 0) { |
| 59 | + blue = 31; |
| 60 | + green = 2 * (value % 32); |
| 61 | + red = 0; |
| 62 | + } |
| 63 | + if (quadrant == 1) { |
| 64 | + blue = 31 - (value % 32); |
| 65 | + green = 63; |
| 66 | + red = 0; |
| 67 | + } |
| 68 | + if (quadrant == 2) { |
| 69 | + blue = 0; |
| 70 | + green = 63; |
| 71 | + red = value % 32; |
| 72 | + } |
| 73 | + if (quadrant == 3) { |
| 74 | + blue = 0; |
| 75 | + green = 63 - 2 * (value % 32); |
| 76 | + red = 31; |
| 77 | + } |
| 78 | + return (red << 11) + (green << 5) + blue; |
| 79 | +} |
| 80 | + |
| 81 | +// ========================================================================= |
| 82 | +// Loop |
| 83 | +// ========================================================================= |
| 84 | +void loop() { |
| 85 | + |
| 86 | + // drawSpot is for small anti-aliased circles, coordinates and radius are |
| 87 | + // floating point to allow sub-pixel positioning (large circles will |
| 88 | + // be slow to draw). Use fillSmoothCircle() for large circles. |
| 89 | + // In this case black is the background colour for the anti-aliasing |
| 90 | + float x = 10.5; |
| 91 | + float y = 10.5; |
| 92 | + float r = 8.6; |
| 93 | + tft.drawSpot(x, y, r, WHITE, BLACK); |
| 94 | + |
| 95 | + // Fill sprite with a colour |
| 96 | + spr.fillSprite(RED); |
| 97 | + // Draw spot in sprite, the background colour is omitted so function |
| 98 | + // reads background colour for aliasing. (To use this method with direct write |
| 99 | + // to TFT (tft.drawSpot...) requires the capability to read data from the TFT!) |
| 100 | + spr.drawSpot(x, y, r, WHITE); |
| 101 | + spr.pushSprite(21, 0); |
| 102 | + |
| 103 | + |
| 104 | + // Draw a segmented ring meter type display |
| 105 | + // Centre of screen |
| 106 | + int cx = tft.width() / 2; |
| 107 | + int cy = tft.height() / 2; |
| 108 | + |
| 109 | + // Inner and outer radius of ring |
| 110 | + float r1 = min(cx, cy) - 40.0; |
| 111 | + float r2 = min(cx, cy) - 10.0; |
| 112 | + |
| 113 | + // Inner and outer line width |
| 114 | + int w1 = r1 / 25; |
| 115 | + int w2 = r2 / 20; |
| 116 | + |
| 117 | + // The following will be updated by the getCoord function |
| 118 | + float px1 = 0.0; |
| 119 | + float py1 = 0.0; |
| 120 | + float px2 = 0.0; |
| 121 | + float py2 = 0.0; |
| 122 | + |
| 123 | + // Wedge line function, an anti-aliased wide line between 2 points, with different |
| 124 | + // line widths at the two ends. Background colour is black. |
| 125 | + for (int angle = -130; angle <= 130; angle += 10) { |
| 126 | + getCoord(cx, cy, &px1, &py1, &px2, &py2, r1, r2, angle); |
| 127 | + uint16_t colour = rainbow(map(angle, -130, 130, 0, 127)); |
| 128 | + if (angle > 45) colour = GRAY; |
| 129 | + tft.drawWedgeLine(px1, py1, px2, py2, w1, w2, colour, BLACK); |
| 130 | + } |
| 131 | + |
| 132 | + // Smooth dark red filled circle |
| 133 | + tft.fillSmoothCircle(cx, cy, r1 - 8, MAROON, BLACK); |
| 134 | + |
| 135 | + // Draw a white dial pointer using wedge line function |
| 136 | + getCoord(cx, cy, &px1, &py1, &px2, &py2, 0, r1 - 10, 45); |
| 137 | + // Magenta wedge line pointer on red background |
| 138 | + // Line tapers from radius 5 to zero |
| 139 | + tft.drawWedgeLine(cx, cy, px2, py2, 5, 0, WHITE, MAROON); |
| 140 | + |
| 141 | + delay(5000); |
| 142 | + |
| 143 | + // Test wideLine function |
| 144 | + tft.fillScreen(BLACK); |
| 145 | + |
| 146 | + // Line width |
| 147 | + int wd = 5; |
| 148 | + |
| 149 | + // Screen limits |
| 150 | + int w = tft.width() - wd; |
| 151 | + int h = tft.height() - wd; |
| 152 | + |
| 153 | + // Line end coords |
| 154 | + int x1 = w - 1; |
| 155 | + int x2 = w - 1; |
| 156 | + int y1 = h - 1; |
| 157 | + int y2 = wd; |
| 158 | + |
| 159 | + for (x2 = wd; x2 < w; x2 += wd * 3) tft.drawWideLine(x1, y1, x2, y2, wd, WHITE, BLACK); |
| 160 | + |
| 161 | + x2 = wd; |
| 162 | + for (y2 = wd; y2 < h; y2 += wd * 4) tft.drawWideLine(x1, y1, x2, y2, wd, WHITE, BLACK); |
| 163 | + |
| 164 | + delay(5000); |
| 165 | + |
| 166 | + // Demo filled smooth rounded rectangle |
| 167 | + tft.fillScreen(BLACK); |
| 168 | + |
| 169 | + x1 = 30; |
| 170 | + y1 = 30; |
| 171 | + w = tft.width() - 2 * x1; |
| 172 | + h = tft.height() - 2 * y1; |
| 173 | + int rad = 30; |
| 174 | + |
| 175 | + tft.fillSmoothRoundRect(x1, y1, w, h, rad, CYAN, BLACK); |
| 176 | + |
| 177 | + // Wait forever |
| 178 | + while (1) delay(100); |
| 179 | +} |
| 180 | + |
| 181 | + |
| 182 | +// ---------------------------------------------------------------- |
| 183 | + |
| 184 | +int main() { |
| 185 | + |
| 186 | + stdio_init_all(); |
| 187 | + |
| 188 | + setup(); |
| 189 | + |
| 190 | + while (true) { |
| 191 | + loop(); |
| 192 | + } |
| 193 | +} |
| 194 | +// ---------------------------------------------------------------- |
0 commit comments