#include #include "SPI.h" #include #include extern "C" { #include "hsv2rgb.h" #include "sin1.h" } const char name[] = "Your Name"; #define SPI0_SCK 2 #define SPI0_MISO GFX_NOT_DEFINED #define SPI0_MOSI 3 #define DISP_NSS 1 #define DISP_RESET 4 #define DISP_DC 5 #define TEXT_MAX_SIZE 5 #define TEXT_BORDER_COLOR DARKGREY #define ROT_SIZE (14 * TEXT_MAX_SIZE) #define TRANSPARENT_BG CYAN #define LETTER_SPACING 1942 // user-configurable Arduino_DataBus *bus = new Arduino_RPiPicoSPI(DISP_DC, DISP_NSS, SPI0_SCK, SPI0_MOSI, SPI0_MISO, spi0); Arduino_GFX *disp = new Arduino_GC9A01(bus, DISP_RESET, 0 /* rotation */, true /* IPS */); Arduino_Canvas *dout = new Arduino_Canvas(240 /* width */, 240 /* height */, disp); Arduino_Canvas *drot = new Arduino_Canvas(ROT_SIZE, ROT_SIZE, disp); color_hsv hsv = {0, 255, 255}; color_rgb rgb; void setup() { Serial.begin(115200); Serial.println("starting..."); delay(50); bus->begin(90000000); if (!disp->begin()) { Serial.println("failed to start disp"); } dout->begin(); dout->fillScreen(BLACK); dout->flush(); drot->begin(); drot->setFont(u8g2_font_cubic11_h_cjk); // u8g2_font_spleen16x32_mr } int16_t render_drot_printchar(const char *str, uint8_t idx, uint8_t size, uint16_t color) { if (size > TEXT_MAX_SIZE) size = TEXT_MAX_SIZE; // clear the rotation buffer drot->fillScreen(TRANSPARENT_BG); // print the letter to the center of the rotation buffer drot->setCursor(1, (size * 10)); drot->setTextColor(color); drot->print(str[idx]); return drot->getCursorX() - size + 1; } void render_drot_border(int8_t x_width, uint16_t text_color, uint16_t border_color) { uint16_t *src, *dst; int16_t x, y; uint8_t is_color; // framebuffer pointers src = drot->getFramebuffer(); dst = dout->getFramebuffer(); // naive bordering for (y = 0; y < ROT_SIZE; y++) { is_color = 0; for (x = 0; x < x_width; x++) { if (is_color) { if (src[x + (y * ROT_SIZE)] != text_color) { is_color = 0; src[x + (y * ROT_SIZE)] = border_color; } } else { if (src[x + (y * ROT_SIZE)] == text_color) { is_color = 1; src[x + (y * ROT_SIZE) - 1] = border_color; } } } } for (x = 0; x < x_width; x++) { is_color = 0; for (y = 0; y < ROT_SIZE; y++) { if (is_color) { if (src[x + (y * ROT_SIZE)] != text_color) { is_color = 0; src[x + (y * ROT_SIZE)] = border_color; } } else { if (src[x + (y * ROT_SIZE)] == text_color) { is_color = 1; src[x + (y * ROT_SIZE) - ROT_SIZE] = border_color; } } } } } void render_drot_rotate(int16_t x_width, int16_t rot, int16_t out_x, int16_t out_y) { int16_t x, y; int16_t nx, ny; int16_t sx, sy; uint16_t *src, *dst; uint16_t src_pxl; // position int16_t start_x = out_x + 120; int16_t start_y = out_y + 120; // framebuffer pointers src = drot->getFramebuffer(); dst = dout->getFramebuffer(); // rotate+copy the buffer for (y = 0; y < ROT_SIZE; y++) { for (x = 0; x < x_width; x++) { src_pxl = src[x + (y * ROT_SIZE)]; sx = x + 1 - (x_width >> 1); sy = y - (ROT_SIZE/2) + 1; if (src_pxl != TRANSPARENT_BG) { nx = ((sx * cos1(rot)) - (sy * sin1(rot))) >> 15; ny = ((sx * sin1(rot)) + (sy * cos1(rot))) >> 15; nx += start_x; ny += start_y; if ((nx >= 0) && (nx < 240)) { if ((ny >= 0) && (ny < 240)) { dst[nx + (ny*240)] = src_pxl; } } } } } } void text_print_circular(const char *str, uint8_t text_size, int16_t spacing, uint16_t fcolor, uint16_t bcolor, int16_t rot) { uint8_t i; int16_t x_width; int16_t x, y; int16_t out_x, out_y; if (text_size > TEXT_MAX_SIZE) text_size = TEXT_MAX_SIZE; drot->setTextSize(text_size); for (i = 0; i < strlen(name); i++) { x = cos1(rot); x = (x >> 9) + (x >> 11) + (x >> 12); y = sin1(rot); y = (y >> 9) + (y >> 11) + (y >> 12); x_width = render_drot_printchar(str, i, text_size, fcolor); // render character render_drot_border(x_width, fcolor, bcolor); // add border to character render_drot_rotate(x_width, rot + 0x6000, x, y); rot -= spacing; } } int16_t trot = 0; int16_t brot = 0; #define HUE_MIN 0x2000-300 #define HUE_MAX 0x2000+300 #define HUE_STEP 3 int16_t huecycle = 0; uint8_t huedir = 0; int16_t satcycle = 0; uint8_t satdir = 0; void bg_huesatcycle() { dout->fillScreen(BLACK); // hue between limits if (!huedir) huecycle += HUE_STEP; else huecycle -= HUE_STEP; if (huecycle > HUE_MAX) { huedir = 1; huecycle = HUE_MAX; } if (huecycle < HUE_MIN) { huedir = 0; huecycle = HUE_MIN; } // saturation if (!satdir) satcycle++; else satcycle--; if (satcycle > 240) { satdir = 1; satcycle = 240; } if (satcycle < 20) { satdir = 0; satcycle = 60; } hsv.h = huecycle >> 3; hsv.s = satcycle; // draw some circles for (int8_t i = 120; i > 0; i--) { hsv.h += 2; hsv.h %= 1536; hsv2rgb_8b(hsv.h, hsv.s, (i * 2), &rgb.r, &rgb.g, &rgb.b); dout->drawCircle(120, 120, i, dout->color565(rgb.r, rgb.g, rgb.b)); } } void bg_rainbow_circles(uint8_t saturation) { uint16_t hue; // speed hsv.h += 24; // background fill ("X" pattern) // hue = hsv.h + 512; // hsv.h %= 1536; // hsv2rgb_8b(hue, 255, 128, &rgb.r, &rgb.g, &rgb.b); // dout->fillScreen(dout->color565(rgb.r, rgb.g, rgb.b)); dout->fillScreen(BLACK); // draw some circles hue = hsv.h; for (int8_t i = 120; i > 0; i--) { hue += 2; hue %= 1536; // "flat" mode, same brightness hsv2rgb_8b(hue, saturation, 192, &rgb.r, &rgb.g, &rgb.b); // "tunnel" mode, darker center // hsv2rgb_8b(hue, saturation, (i * 2), &rgb.r, &rgb.g, &rgb.b); dout->drawCircle(120, 120, i, dout->color565(rgb.r, rgb.g, rgb.b)); } } void bg_radarsweep(int16_t rot, int16_t offset, uint8_t lines) { color_rgb rgb; uint16_t w; int16_t x, y; if (lines == 0xff) lines--; dout->fillScreen(BLACK); for (uint8_t i = 0; i < lines; i++) { // linear fade w = 256 * lines; w -= (256 * i); w /= lines; w &= 0xff; // todo: exponential fade or something // get rotational point x = cos1(rot); x = (x >> 8); y = sin1(rot); y = (y >> 8); hsv2rgb_8b((1536/3), 200, (i > 4) ? (w >> 1) : w, &rgb.r, &rgb.g, &rgb.b); dout->drawLine(x + 120, y + 120, 128, 128, dout->color565(rgb.r, rgb.g, rgb.b)); rot -= offset; } } void texthue_180degree() { uint16_t hue; hue = hsv.h + 768; hue %= 1536; hsv2rgb_8b(hue, 224, 64, &rgb.r, &rgb.g, &rgb.b); } void texthue_huesatcycle_circles() { uint16_t hue; hue = (huecycle - 0x2000); if (hue > (1536 << 3)) hue += (1536 << 3); hsv2rgb_8b(hue >> 3, 224, 64, &rgb.r, &rgb.g, &rgb.b); } void loop() { uint16_t hue; color_rgb fc, bc; // rainbow circles program // bg_rainbow_circles(200); // texthue_180degree(); brot += 400; bg_radarsweep(brot, 25, 200); // small hue shift with larger saturation shifts circles // bg_huesatcycle_circles(); // texthue_huesatcycle(); // text rotation - black text, default border trot += 420 - 69; fc.r = fc.g = fc.b = 240; bc.r = bc.g = bc.b = 32; text_print_circular(name, TEXT_MAX_SIZE, LETTER_SPACING, dout->color565(fc.r, fc.g, fc.b), dout->color565(bc.r, bc.g, bc.b), trot); dout->flush(); }