123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554 |
- /*
- * GFX_FUNCTIONS.c
- *
- * Created on: 30-Oct-2020
- * Author: meh
- */
- #include <ST7735.h>
- #include "stdint.h"
- #include "stdlib.h"
- extern int16_t _width; ///< Display width as modified by current rotation
- extern int16_t _height; ///< Display height as modified by current rotation
- extern int16_t cursor_x; ///< x location to start print()ing text
- extern int16_t cursor_y; ///< y location to start print()ing text
- extern uint8_t rotation; ///< Display rotation (0 thru 3)
- extern uint8_t _colstart; ///< Some displays need this changed to offset
- extern uint8_t _rowstart; ///< Some displays need this changed to offset
- extern uint8_t _xstart;
- extern uint8_t _ystart;
- void drawPixel(int16_t x, int16_t y, uint16_t color)
- {
- ST7735_DrawPixel(x, y, color);
- }
- void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
- {
- ST7735_FillRectangle(x, y, w, h, color);
- }
- /***********************************************************************************************************/
- #define _swap_int16_t(a, b) \
- { \
- int16_t t = a; \
- a = b; \
- b = t; \
- }
- #define min(a, b) (((a) < (b)) ? (a) : (b))
- void writePixel(int16_t x, int16_t y, uint16_t color)
- {
- drawPixel(x, y, color);
- }
- void writeLine(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) {
- writePixel(y0, x0, color);
- } else {
- writePixel(x0, y0, color);
- }
- err -= dy;
- if (err < 0) {
- y0 += ystep;
- err += dx;
- }
- }
- }
- void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
- {
- writeLine(x, y, x, y + h - 1, color);
- }
- void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
- {
- writeLine(x, y, x + w - 1, y, color);
- }
- void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color)
- {
- if(x0 == x1){
- if(y0 > y1) _swap_int16_t(y0, y1);
- drawFastVLine(x0, y0, y1 - y0 + 1, color);
- } else if(y0 == y1){
- if(x0 > x1) _swap_int16_t(x0, x1);
- drawFastHLine(x0, y0, x1 - x0 + 1, color);
- } else {
- writeLine(x0, y0, x1, y1, color);
- }
- }
- 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;
- writePixel(x0 , y0+r, color);
- writePixel(x0 , y0-r, color);
- writePixel(x0+r, y0 , color);
- writePixel(x0-r, y0 , color);
- while (x<y) {
- if (f >= 0) {
- y--;
- ddF_y += 2;
- f += ddF_y;
- }
- x++;
- ddF_x += 2;
- f += ddF_x;
- writePixel(x0 + x, y0 + y, color);
- writePixel(x0 - x, y0 + y, color);
- writePixel(x0 + x, y0 - y, color);
- writePixel(x0 - x, y0 - y, color);
- writePixel(x0 + y, y0 + x, color);
- writePixel(x0 - y, y0 + x, color);
- writePixel(x0 + y, y0 - x, color);
- writePixel(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) {
- writePixel(x0 + x, y0 + y, color);
- writePixel(x0 + y, y0 + x, color);
- }
- if (cornername & 0x2) {
- writePixel(x0 + x, y0 - y, color);
- writePixel(x0 + y, y0 - x, color);
- }
- if (cornername & 0x8) {
- writePixel(x0 - y, y0 + x, color);
- writePixel(x0 - x, y0 + y, color);
- }
- if (cornername & 0x1) {
- writePixel(x0 - y, y0 - x, color);
- writePixel(x0 - x, y0 - y, color);
- }
- }
- }
- void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t corners, 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;
- int16_t px = x;
- int16_t py = y;
- delta++; // Avoid some +1's in the loop
- while(x < y) {
- if (f >= 0) {
- y--;
- ddF_y += 2;
- f += ddF_y;
- }
- x++;
- ddF_x += 2;
- f += ddF_x;
- // These checks avoid double-drawing certain lines, important
- // for the SSD1306 library which has an INVERT drawing mode.
- if(x < (y + 1)) {
- if(corners & 1) drawFastVLine(x0+x, y0-y, 2*y+delta, color);
- if(corners & 2) drawFastVLine(x0-x, y0-y, 2*y+delta, color);
- }
- if(y != py) {
- if(corners & 1) drawFastVLine(x0+py, y0-px, 2*px+delta, color);
- if(corners & 2) drawFastVLine(x0-py, y0-px, 2*px+delta, color);
- py = y;
- }
- px = x;
- }
- }
- void fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color)
- {
- drawFastVLine(x0, y0-r, 2*r+1, color);
- fillCircleHelper(x0, y0, r, 3, 0, color);
- }
- void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
- {
- drawFastHLine(x, y, w, color);
- drawFastHLine(x, y+h-1, w, color);
- drawFastVLine(x, y, h, color);
- drawFastVLine(x+w-1, y, h, color);
- }
- void drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color)
- {
- int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
- if(r > max_radius) r = max_radius;
- // smarter version
- drawFastHLine(x+r , y , w-2*r, color); // Top
- drawFastHLine(x+r , y+h-1, w-2*r, color); // Bottom
- drawFastVLine(x , y+r , h-2*r, color); // Left
- drawFastVLine(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);
- }
- void fillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color)
- {
- int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
- if(r > max_radius) r = max_radius;
- // smarter version
- fillRect(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);
- }
- 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);
- }
- 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;
- drawFastHLine(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);
- 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 = (int32_t)dx12 * (y - y1);
- sb = (int32_t)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);
- drawFastHLine(a, y, b-a+1, color);
- }
- }
- void fillScreen(uint16_t color) {
- fillRect(0, 0, _width, _height, color);
- }
- void testLines(uint16_t color)
- {
- int x1, y1, x2, y2,
- w = _width,
- h = _height;
- fillScreen(BLACK);
- x1 = y1 = 0;
- y2 = h - 1;
- for (x2 = 0; x2 < w; x2 += 6) drawLine(x1, y1, x2, y2, color);
- x2 = w - 1;
- for (y2 = 0; y2 < h; y2 += 6) drawLine(x1, y1, x2, y2, color);
- fillScreen(BLACK);
- x1 = w - 1;
- y1 = 0;
- y2 = h - 1;
- for (x2 = 0; x2 < w; x2 += 6) drawLine(x1, y1, x2, y2, color);
- x2 = 0;
- for (y2 = 0; y2 < h; y2 += 6) drawLine(x1, y1, x2, y2, color);
- fillScreen(BLACK);
- x1 = 0;
- y1 = h - 1;
- y2 = 0;
- for (x2 = 0; x2 < w; x2 += 6) drawLine(x1, y1, x2, y2, color);
- x2 = w - 1;
- for (y2 = 0; y2 < h; y2 += 6) drawLine(x1, y1, x2, y2, color);
- fillScreen(BLACK);
- x1 = w - 1;
- y1 = h - 1;
- y2 = 0;
- for (x2 = 0; x2 < w; x2 += 6) drawLine(x1, y1, x2, y2, color);
- x2 = 0;
- for (y2 = 0; y2 < h; y2 += 6) drawLine(x1, y1, x2, y2, color);
- }
- void testFastLines(uint16_t color1, uint16_t color2)
- {
- int x, y, w = _width, h = _height;
- fillScreen(BLACK);
- for (y = 0; y < h; y += 5) drawFastHLine(0, y, w, color1);
- for (x = 0; x < w; x += 5) drawFastVLine(x, 0, h, color2);
- }
- void testRects(uint16_t color)
- {
- int n, i, i2,
- cx = _width / 2,
- cy = _height / 2;
- fillScreen(BLACK);
- n = min(_width, _height);
- for (i = 2; i < n; i += 6) {
- i2 = i / 2;
- drawRect(cx - i2, cy - i2, i, i, color);
- }
- }
- void testFilledRects(uint16_t color1, uint16_t color2)
- {
- int n, i, i2,
- cx = _width / 2 - 1,
- cy = _height / 2 - 1;
- fillScreen(BLACK);
- n = min(_width, _height);
- for (i = n; i > 0; i -= 6) {
- i2 = i / 2;
- fillRect(cx - i2, cy - i2, i, i, color1);
- drawRect(cx - i2, cy - i2, i, i, color2);
- }
- }
- void testFilledCircles(uint8_t radius, uint16_t color)
- {
- int x, y, w = _width, h = _height, r2 = radius * 2;
- fillScreen(BLACK);
- for (x = radius; x < w; x += r2) {
- for (y = radius; y < h; y += r2) {
- fillCircle(x, y, radius, color);
- }
- }
- }
- void testCircles(uint8_t radius, uint16_t color)
- {
- int x, y, r2 = radius * 2,
- w = _width + radius,
- h = _height + radius;
- // Screen is not cleared for this one -- this is
- // intentional and does not affect the reported time.
- for (x = 0; x < w; x += r2) {
- for (y = 0; y < h; y += r2) {
- drawCircle(x, y, radius, color);
- }
- }
- }
- void testTriangles()
- {
- int n, i, cx = _width / 2 - 1,
- cy = _height / 2 - 1;
- fillScreen(BLACK);
- n = min(cx, cy);
- for (i = 0; i < n; i += 5) {
- drawTriangle(
- cx , cy - i, // peak
- cx - i, cy + i, // bottom left
- cx + i, cy + i, // bottom right
- color565(0, 0, i));
- }
- }
- void testFilledTriangles() {
- int i, cx = _width / 2 - 1,
- cy = _height / 2 - 1;
- fillScreen(BLACK);
- for (i = min(cx, cy); i > 10; i -= 5) {
- fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
- color565(0, i, i));
- drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
- color565(i, i, 0));
- }
- }
- void testRoundRects() {
- int w, i, i2, red, step,
- cx = _width / 2 - 1,
- cy = _height / 2 - 1;
- fillScreen(BLACK);
- w = min(_width, _height);
- red = 0;
- step = (256 * 6) / w;
- for (i = 0; i < w; i += 6) {
- i2 = i / 2;
- red += step;
- drawRoundRect(cx - i2, cy - i2, i, i, i / 8, color565(red, 0, 0));
- }
- }
- void testFilledRoundRects() {
- int i, i2, green, step,
- cx = _width / 2 - 1,
- cy = _height / 2 - 1;
- fillScreen(BLACK);
- green = 256;
- step = (256 * 6) / min(_width, _height);
- for (i = min(_width, _height); i > 20; i -= 6) {
- i2 = i / 2;
- green -= step;
- fillRoundRect(cx - i2, cy - i2, i, i, i / 8, color565(0, green, 0));
- }
- }
- void testFillScreen()
- {
- fillScreen(BLACK);
- fillScreen(RED);
- fillScreen(GREEN);
- fillScreen(BLUE);
- fillScreen(BLACK);
- }
- void testAll (void)
- {
- testFillScreen();
- testLines(CYAN);
- testFastLines(RED, BLUE);
- testRects(GREEN);
- testFilledRects(YELLOW, MAGENTA);
- testFilledCircles(10, MAGENTA);
- testCircles(10, WHITE);
- testTriangles();
- testFilledTriangles();
- testRoundRects();
- testFilledRoundRects();
- }
|