Split text rotation rendering into multiple steps

Doing this I can reuse code for other text transforms
This commit is contained in:
true 2023-11-05 09:27:22 -08:00
parent fba3dc7639
commit 04759ec9df
1 changed files with 184 additions and 180 deletions

View File

@ -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();
}