Files
velometer/graphics.c

226 lines
6.7 KiB
C

#include "graphics.h"
#include "font_ubuntu.h"
#include "utf8.h"
#include <pico/stdlib.h>
void lcd_draw_horizontal_digit_segment(uint16_t x, uint16_t y, uint16_t color) {
x += LCD_OFFSET_X;
y += LCD_OFFSET_Y;
uint16_t y1 = y + 8;
uint16_t x0 = x + 7;
uint16_t w = 32;
for (int i = y; i < y1; ++i, w += 2, --x0) {
_draw_h_strip(x0, i, w, color);
}
x0 += 2;
w -= 4;
y = y1;
y1 = y + 7;
for (int i = y; i < y1; ++i, w -= 2, ++x0) {
_draw_h_strip(x0, i, w, color);
}
}
void lcd_draw_vertical_digit_segment(uint16_t x, uint16_t y, uint16_t color) {
x += LCD_OFFSET_X;
y += LCD_OFFSET_Y;
uint16_t x1 = x + 8;
uint16_t y0 = y + 7;
uint16_t h = 32;
for (int i = x; i < x1; ++i, h += 2, --y0) {
_draw_v_strip(i, y0, h, color);
}
y0 += 2;
h -= 4;
x = x1;
x1 = x + 7;
for (int i = x; i < x1; ++i, h -= 2, ++y0) {
_draw_v_strip(i, y0, h, color);
}
}
void lcd_draw_horizontal_small_digit_segment(uint16_t x, uint16_t y, uint16_t color) {
x += LCD_OFFSET_X;
y += LCD_OFFSET_Y;
uint16_t y1 = y + 6;
uint16_t x0 = x + 5;
uint16_t w = 24;
for (int i = y; i < y1; ++i, w += 2, --x0) {
_draw_h_strip(x0, i, w, color);
}
x0 += 2;
w -= 4;
y = y1;
y1 = y + 5;
for (int i = y; i < y1; ++i, w -= 2, ++x0) {
_draw_h_strip(x0, i, w, color);
}
}
void lcd_draw_vertical_small_digit_segment(uint16_t x, uint16_t y, uint16_t color) {
x += LCD_OFFSET_X;
y += LCD_OFFSET_Y;
uint16_t x1 = x + 6;
uint16_t y0 = y + 5;
uint16_t h = 24;
for (int i = x; i < x1; ++i, h += 2, --y0) {
_draw_v_strip(i, y0, h, color);
}
y0 += 2;
h -= 4;
x = x1;
x1 = x + 5;
for (int i = x; i < x1; ++i, h -= 2, ++y0) {
_draw_v_strip(i, y0, h, color);
}
}
void lcd_draw_horizontal_xsmall_digit_segment(uint16_t x, uint16_t y, uint16_t color) {
x += LCD_OFFSET_X;
y += LCD_OFFSET_Y;
uint16_t y1 = y + 4;
uint16_t x0 = x + 3;
uint16_t w = 16;
for (int i = y; i < y1; ++i, w += 2, --x0) {
_draw_h_strip(x0, i, w, color);
}
x0 += 2;
w -= 4;
y = y1;
y1 = y + 3;
for (int i = y; i < y1; ++i, w -= 2, ++x0) {
_draw_h_strip(x0, i, w, color);
}
}
void lcd_draw_vertical_xsmall_digit_segment(uint16_t x, uint16_t y, uint16_t color) {
x += LCD_OFFSET_X;
y += LCD_OFFSET_Y;
uint16_t x1 = x + 4;
uint16_t y0 = y + 3;
uint16_t h = 16;
for (int i = x; i < x1; ++i, h += 2, --y0) {
_draw_v_strip(i, y0, h, color);
}
y0 += 2;
h -= 4;
x = x1;
x1 = x + 3;
for (int i = x; i < x1; ++i, h -= 2, ++y0) {
_draw_v_strip(i, y0, h, color);
}
}
static const uint8_t DIGIT_MASKS[10] = {0b1110111, 0b0100100, 0b1011101, 0b1101101, 0b0101110,
0b1101011, 0b1111011, 0b0100101, 0b1111111, 0b1101111};
void lcd_draw_digit(uint8_t digit, uint16_t x, uint16_t y, uint16_t color, uint16_t bgColor) {
const uint16_t SEGMENT_OFFSETS[7][2] = {{9, 0}, {0, 9}, {49, 9}, {9, 49}, {0, 58}, {49, 58}, {9, 99}};
for (int seg = 0; seg < 7; ++seg) {
uint16_t segColor = ((DIGIT_MASKS[digit] >> seg) & 1) ? color : bgColor;
if (seg == 0 || seg == 3 || seg == 6)
lcd_draw_horizontal_digit_segment(x + SEGMENT_OFFSETS[seg][0], y + SEGMENT_OFFSETS[seg][1], segColor);
else
lcd_draw_vertical_digit_segment(x + SEGMENT_OFFSETS[seg][0], y + SEGMENT_OFFSETS[seg][1], segColor);
}
}
void lcd_draw_small_digit(uint8_t digit, uint16_t x, uint16_t y, uint16_t color, uint16_t bgColor) {
const uint16_t SEGMENT_OFFSETS[7][2] = {{7, 0}, {0, 7}, {37, 7}, {7, 37}, {0, 44}, {37, 44}, {7, 74}};
for (int seg = 0; seg < 7; ++seg) {
uint16_t segColor = ((DIGIT_MASKS[digit] >> seg) & 1) ? color : bgColor;
if (seg == 0 || seg == 3 || seg == 6)
lcd_draw_horizontal_small_digit_segment(x + SEGMENT_OFFSETS[seg][0], y + SEGMENT_OFFSETS[seg][1], segColor);
else
lcd_draw_vertical_small_digit_segment(x + SEGMENT_OFFSETS[seg][0], y + SEGMENT_OFFSETS[seg][1], segColor);
}
}
void lcd_draw_xsmall_digit(uint8_t digit, uint16_t x, uint16_t y, uint16_t color, uint16_t bgColor) {
const uint16_t SEGMENT_OFFSETS[7][2] = {{4, 0}, {0, 4}, {23, 4}, {4, 23}, {0, 27}, {23, 27}, {4, 46}};
for (int seg = 0; seg < 7; ++seg) {
uint16_t segColor = ((DIGIT_MASKS[digit] >> seg) & 1) ? color : bgColor;
if (seg == 0 || seg == 3 || seg == 6)
lcd_draw_horizontal_xsmall_digit_segment(x + SEGMENT_OFFSETS[seg][0], y + SEGMENT_OFFSETS[seg][1], segColor);
else
lcd_draw_vertical_xsmall_digit_segment(x + SEGMENT_OFFSETS[seg][0], y + SEGMENT_OFFSETS[seg][1], segColor);
}
}
void lcd_draw_decimal_point(uint16_t x, uint16_t y, uint16_t color) {
x += LCD_OFFSET_X;
y += LCD_OFFSET_Y;
for (int i = 0; i < 5; ++i) {
_draw_h_strip(x + 4 - i, y + i, 8 + i, color);
}
for (int i = 5; i < 9; ++i) {
_draw_h_strip(x, y + i, 12, color);
}
for (int i = 9; i < 13; ++i) {
_draw_h_strip(x, y + i, 20 - i, color);
}
}
void lcd_write_string(const char *string, uint16_t x, uint16_t y, uint16_t color, uint16_t bgColor) {
x += LCD_OFFSET_X;
y += LCD_OFFSET_Y;
static uint16_t glyphPixels[24 * 24];
while (*string) {
int character = decode_code_point(&string);
if (character != 32) {
int glyphIndex = glyph_index_for_code_point(character);
const uint8_t *glyph;
int8_t glyphWidth;
if (glyphIndex != -1) {
glyph = GLYPH_ADDR[glyphIndex];
glyphWidth = GLYPH_WIDTH[glyphIndex];
} else {
glyph = GLYPH_MISSING;
glyphWidth = 12;
}
int row = 0, col = 0;
for (int byte = 0; byte < glyphWidth * 3; ++byte) {
int rem = glyph[byte];
for (int bit = 0; bit < 8; ++bit) {
glyphPixels[(row * 8 + bit) * (glyphWidth + LETTER_SPACING) + col] = (rem & 1) ? color : bgColor;
rem >>= 1;
}
if (++col == glyphWidth) {
col = 0;
++row;
}
}
for (int j = 0; j < 24; ++j) {
for (int i = 0; i < LETTER_SPACING; ++i)
glyphPixels[j * (glyphWidth + LETTER_SPACING) + glyphWidth + i] = 0;
}
st7789_caset(x, x + glyphWidth + LETTER_SPACING - 1);
st7789_raset(y, y + 24 - 1);
st7789_write(glyphPixels, 24 * (glyphWidth + LETTER_SPACING) * sizeof(uint16_t));
x += glyphWidth + LETTER_SPACING;
} else {
_fill_rectangle(x, y, 12, 24, bgColor);
x += 12;
}
}
}
int lcd_string_width(const char *string) {
int width = 0;
while (*string) {
int character = decode_code_point(&string);
if (character == 32) {
width += 12;
continue;
} else {
int glyphIndex = glyph_index_for_code_point(character);
if (glyphIndex != -1) {
width += GLYPH_WIDTH[glyphIndex] + LETTER_SPACING;
} else {
width += 12;
}
}
}
return width;
}