From 04759ec9df014fd578bfe2c9d28cedafd066f3fb Mon Sep 17 00:00:00 2001 From: true Date: Sun, 5 Nov 2023 09:27:22 -0800 Subject: [PATCH] Split text rotation rendering into multiple steps Doing this I can reuse code for other text transforms --- src/main.cpp | 364 ++++++++++++++++++++++++++------------------------- 1 file changed, 184 insertions(+), 180 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index a683c2f..0062702 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,19 +14,21 @@ const char name[] = "Your Name"; -#define SPI0_SCK 2 -#define SPI0_MISO GFX_NOT_DEFINED -#define SPI0_MOSI 3 +#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 DISP_NSS 1 +#define DISP_RESET 4 +#define DISP_DC 5 -#define TEXT_SIZE 5 -#define BORDER_COLOR DARKGREY -#define ROT_SIZE 70 +#define TEXT_MAX_SIZE 5 +#define TEXT_BORDER_COLOR DARKGREY -#define LETTER_SPACING 1942 // user-configurable +#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); @@ -35,116 +37,107 @@ Arduino_GFX *disp = new Arduino_GC9A01(bus, DISP_RESET, 0 /* rotation */, true / 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.begin(115200); - Serial.println("starting..."); + Serial.println("starting..."); - delay(50); + delay(50); - bus->begin(90000000); + bus->begin(90000000); - if (!disp->begin()) { - Serial.println("failed to start disp"); - } + if (!disp->begin()) { + Serial.println("failed to start disp"); + } - dout->begin(); - dout->fillScreen(BLACK); - dout->flush(); + dout->begin(); + dout->fillScreen(BLACK); + dout->flush(); - drot->begin(); - drot->setFont(u8g2_font_cubic11_h_cjk); // u8g2_font_spleen16x32_mr - drot->setTextSize(TEXT_SIZE); + drot->begin(); + drot->setFont(u8g2_font_cubic11_h_cjk); // u8g2_font_spleen16x32_mr } -void rotate_letter(uint8_t idx, int16_t rot, int16_t out_x, int16_t out_y, uint16_t color) +int16_t render_drot_printchar(const char *str, uint8_t idx, uint8_t size, uint16_t color) { - int16_t x, y; - int16_t nx, ny; - int16_t sx, sy; + if (size > TEXT_MAX_SIZE) size = TEXT_MAX_SIZE; - int16_t start_x, start_y; + // clear the rotation buffer + drot->fillScreen(TRANSPARENT_BG); - int16_t x_width; + // 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; +} - uint16_t *src, *dst; - uint16_t src_pxl; - uint16_t bgcolor = CYAN; +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; - uint8_t is_color; + // framebuffer pointers + src = drot->getFramebuffer(); + dst = dout->getFramebuffer(); - // clear the rotation buffer - drot->fillScreen(CYAN); - - // print the letter to the center of the rotation buffer - drot->setCursor(1, (TEXT_SIZE * 10)); - drot->setTextColor(color); - drot->print(name[idx]); - x_width = drot->getCursorX() - TEXT_SIZE + 1; - - // 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)] != color) { - is_color = 0; - src[x + (y * ROT_SIZE)] = BORDER_COLOR; - } - } else { - if (src[x + (y * ROT_SIZE)] == 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)] != color) { - is_color = 0; - src[x + (y * ROT_SIZE)] = BORDER_COLOR; - } - } else { - if (src[x + (y * ROT_SIZE)] == color) { - is_color = 1; - src[x + (y * ROT_SIZE) - ROT_SIZE] = BORDER_COLOR; - } - } - } - } - - // position - start_x = out_x + 120; - start_y = out_y + 120; - - // rotate+copy the buffer - for (y = 0; y < ROT_SIZE; y++) { + // naive bordering + for (y = 0; y < ROT_SIZE; y++) { + is_color = 0; 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 != bgcolor) { + 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; + } + } + } + } +} + +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)) { + ny += start_y; + + if ((nx >= 0) && (nx < 240)) { if ((ny >= 0) && (ny < 240)) { dst[nx + (ny*240)] = src_pxl; } @@ -154,6 +147,31 @@ void rotate_letter(uint8_t idx, int16_t rot, int16_t out_x, int16_t out_y, uint1 } } +void text_print_circular(const char *str, uint8_t text_size, int16_t spacing, uint16_t color, 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, color); // render character + render_drot_border(x_width, color, TEXT_BORDER_COLOR); // add border to character + render_drot_rotate(x_width, rot + 0x6000, x, y); + rot -= spacing; + } +} + int16_t rot = 0; #define HUE_MIN 0x2000-300 @@ -167,120 +185,106 @@ uint8_t satdir = 0; void bg_huesatcycle() { - dout->fillScreen(BLACK); + 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; - } + // 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; - } + // 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; + 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); + // 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)); - } + dout->drawCircle(120, 120, i, dout->color565(rgb.r, rgb.g, rgb.b)); + } } void bg_rainbow_circles(uint8_t saturation) { - uint16_t hue; + uint16_t hue; - // speed - hsv.h += 24; + // 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); + // 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); + // 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)); - } + dout->drawCircle(120, 120, i, dout->color565(rgb.r, rgb.g, rgb.b)); + } } void texthue_180degree() { - uint16_t hue; + uint16_t hue; - hue = hsv.h + 768; - hue %= 1536; - hsv2rgb_8b(hue, 224, 64, &rgb.r, &rgb.g, &rgb.b); + 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); + 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; + uint16_t hue; - // rainbow circles program - bg_rainbow_circles(200); - // texthue_180degree(); - rgb.r = rgb.g = rgb.b = 0; + // rainbow circles program + bg_rainbow_circles(200); + // texthue_180degree(); - // small hue shift with larger saturation shifts circles - // bg_huesatcycle_circles(); - // texthue_huesatcycle(); + // small hue shift with larger saturation shifts circles + // bg_huesatcycle_circles(); + // texthue_huesatcycle(); - // text rotation - rot += 420 - 69; + // text rotation - black text, default border + rot += 420 - 69; + rgb.r = rgb.g = rgb.b = 0; + text_print_circular(name, TEXT_MAX_SIZE, LETTER_SPACING, dout->color565(rgb.r, rgb.g, rgb.b), rot); - int16_t x, y; - int16_t d; - d = rot; - for (uint8_t i = 0; i < strlen(name); i++) { - x = cos1(d); - x = (x >> 9) + (x >> 11) + (x >> 12); - - y = sin1(d); // sin1(d) * 21) / 32; - y = (y >> 9) + (y >> 11) + (y >> 12); - - rotate_letter(i, d + 0x6000, x, y, dout->color565(rgb.r, rgb.g, rgb.b)); - // d -= 9; // for 7-bit version - d -= LETTER_SPACING; // for 15-bit version - } - - dout->flush(); + dout->flush(); } \ No newline at end of file