Wolf-LITE/STM32/Core/Src/lcd_driver.c

404 wiersze
11 KiB
C

#include "settings.h"
//Header files
#include "lcd_driver.h"
#include "main.h"
#include "fonts.h"
#include "functions.h"
static bool _cp437 = false;
static uint16_t text_cursor_y = 0;
static uint16_t text_cursor_x = 0;
static bool wrap = false;
uint16_t LCDDriver_GetCurrentXOffset(void)
{
return text_cursor_x;
}
void LCDDriver_SetCurrentXOffset(uint16_t x)
{
text_cursor_x = x;
}
//Text printing functions
void LCDDriver_drawChar(uint16_t x, uint16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size)
{
if(c < 32) //non-printable
return;
uint8_t line = 0;
if ((x >= LCD_WIDTH) || // Clip right
(y >= LCD_HEIGHT) || // Clip bottom
((x + 6 * size - 1) < 0) || // Clip left
((y + 8 * size - 1) < 0)) // Clip top
return;
if (!_cp437 && (c >= 176))
c++; // Handle 'classic' charset behavior
LCDDriver_SetCursorAreaPosition(x, y, x + 6 * size - 1, y + 8 * size - 1); //char area
for (int8_t j = 0; j < 8; j++)
{ //y line out
for (int8_t s_y = 0; s_y < size; s_y++) //y size scale
for (int8_t i = 0; i < 6; i++)
{ //x line out
{
if (i == 5)
line = 0x0;
else
line = rastr_font[(c * 5) + i]; //read font
line >>= j;
for (int8_t s_x = 0; s_x < size; s_x++) //x size scale
{
if (line & 0x1)
LCDDriver_SendData(color); //font pixel
else
LCDDriver_SendData(bg); //background pixel
}
}
}
}
}
void LCDDriver_printText(char text[], uint16_t x, uint16_t y, uint16_t color, uint16_t bg, uint8_t size)
{
uint16_t offset = size * 6;
uint16_t skipped = 0;
for (uint16_t i = 0; i < 128 && text[i] != 0; i++)
{
if (text[i] == '^' && text[i + 1] == 'o') //celsius
{
i++;
skipped++;
LCDDriver_drawChar(x + (offset * (i - skipped)), y - 3, text[i], color, bg, size);
text_cursor_x = x + (offset * (i + 1 - skipped));
}
else
{
LCDDriver_drawChar(x + (offset * (i - skipped)), y, text[i], color, bg, size);
text_cursor_x = x + (offset * (i + 1 - skipped));
}
}
}
void LCDDriver_drawCharFont(uint16_t x, uint16_t y, unsigned char c, uint16_t color, uint16_t bg, const GFXfont *gfxFont)
{
c -= gfxFont->first;
GFXglyph *glyph = (GFXglyph *)&gfxFont->glyph[c];
uint16_t bo = glyph->bitmapOffset;
uint8_t bits = 0;
uint8_t bit = 0;
int16_t ys1 = y + glyph->yOffset;
int16_t ys2 = y + glyph->yOffset + glyph->height - 1;
if (ys1 < 0)
ys1 = 0;
if (ys2 < 0)
ys2 = 0;
LCDDriver_SetCursorAreaPosition(x, (uint16_t)ys1, x + glyph->xAdvance - 1, (uint16_t)ys2); //char area
for (uint8_t yy = 0; yy < glyph->height; yy++)
{
for (uint8_t xx = 0; xx < glyph->xAdvance; xx++)
{
if (xx < glyph->xOffset || xx >= (glyph->xOffset + glyph->width))
{
LCDDriver_SendData(bg); //background pixel
continue;
}
if (!(bit++ & 7))
{
bits = gfxFont->bitmap[bo++];
}
if (bits & 0x80)
{
LCDDriver_SendData(color); //font pixel
}
else
{
LCDDriver_SendData(bg); //background pixel
}
bits <<= 1;
}
}
}
void LCDDriver_printTextFont(char text[], uint16_t x, uint16_t y, uint16_t color, uint16_t bg, const GFXfont *gfxFont)
{
uint8_t c = 0;
text_cursor_x = x;
text_cursor_y = y;
for (uint16_t i = 0; i < 256 && text[i] != NULL; i++)
{
c = text[i];
if (c == '\n')
{
text_cursor_x = 0;
text_cursor_y += gfxFont->yAdvance;
}
else if (c != '\r')
{
if ((c >= gfxFont->first) && (c <= gfxFont->last))
{
GFXglyph *glyph = (GFXglyph *)&gfxFont->glyph[c - gfxFont->first];
if ((glyph->width > 0) && (glyph->height > 0))
{
if (wrap && ((text_cursor_x + (glyph->xOffset + glyph->width)) > LCD_WIDTH))
{
text_cursor_x = 0;
text_cursor_y += gfxFont->yAdvance;
}
LCDDriver_drawCharFont(text_cursor_x, text_cursor_y, c, color, bg, gfxFont);
}
text_cursor_x += glyph->xAdvance;
}
}
}
}
/**************************************************************************/
/*!
@brief Helper to determine size of a character with current font/size.
Broke this out as it's used by both the PROGMEM- and RAM-resident getTextBounds() functions.
@param c The ascii character in question
@param x Pointer to x location of character
@param y Pointer to y location of character
@param minx Minimum clipping value for X
@param miny Minimum clipping value for Y
@param maxx Maximum clipping value for X
@param maxy Maximum clipping value for Y
*/
/**************************************************************************/
static void LCDDriver_charBounds(char c, uint16_t *x, uint16_t *y, int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy, const GFXfont *gfxFont)
{
if (c == '\n')
{ // Newline?
*x = 0; // Reset x to zero, advance y by one line
*y += gfxFont->yAdvance;
}
else if (c != '\r')
{
if ((c >= gfxFont->first) && (c <= gfxFont->last))
{ // Char present in this font?
GFXglyph *glyph = (GFXglyph *)&gfxFont->glyph[c - gfxFont->first];
if (wrap && ((*x + (((int16_t)glyph->xOffset + glyph->width))) > LCD_WIDTH))
{
*x = 0; // Reset x to zero, advance y by one line
*y += gfxFont->yAdvance;
}
int16_t x1 = *x + glyph->xOffset,
y1 = *y + glyph->yOffset,
x2 = x1 + glyph->width - 1,
y2 = y1 + glyph->height - 1;
if (x1 < *minx)
*minx = x1;
if (y1 < *miny)
*miny = y1;
if (x2 > *maxx)
*maxx = x2;
if (y2 > *maxy)
*maxy = y2;
*x += glyph->xAdvance;
}
}
}
/**************************************************************************/
/*!
@brief Helper to determine size of a string with current font/size. Pass string and a cursor position, returns UL corner and W,H.
@param str The ascii string to measure
@param x The current cursor X
@param y The current cursor Y
@param x1 The boundary X coordinate, set by function
@param y1 The boundary Y coordinate, set by function
@param w The boundary width, set by function
@param h The boundary height, set by function
*/
/**************************************************************************/
void LCDDriver_getTextBounds(char text[], uint16_t x, uint16_t y, uint16_t *x1, uint16_t *y1, uint16_t *w, uint16_t *h, const GFXfont *gfxFont)
{
uint8_t c; // Current character
*x1 = x;
*y1 = y;
*w = *h = 0;
int16_t minx = LCD_WIDTH, miny = LCD_HEIGHT, maxx = 0, maxy = 0;
for (uint16_t i = 0; i < 40 && text[i] != NULL; i++)
{
c = text[i];
LCDDriver_charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy, gfxFont);
}
if (maxx >= minx)
{
*x1 = (uint16_t)minx;
*w = (uint16_t)(maxx - minx + 1);
}
if (maxy >= miny)
{
*y1 = (uint16_t)miny;
*h = (uint16_t)(maxy - miny + 1);
}
}
//Image print (RGB 565, 2 bytes per pixel)
void LCDDriver_printImage(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t *data)
{
uint32_t n = w * h * 2;
LCDDriver_SetCursorAreaPosition(x, y, w + x - 1, h + y - 1);
for (uint32_t i = 0; i < n; i += 2)
{
LCDDriver_SendData((uint16_t)((data[i] << 8) | data[i + 1]));
}
}
void LCDDriver_printImage_RLECompressed(uint16_t x, uint16_t y, const tIMAGE *image, uint16_t transparent_color, uint16_t bg_color)
{
uint32_t pixels = image->width * image->height;
uint32_t i = 0;
uint32_t decoded = 0;
LCDDriver_SetCursorAreaPosition(x, y, image->width + x - 1, image->height + y - 1);
while (true)
{
if ((int16_t)image->data[i] < 0) // no repeats
{
uint16_t count = (-(int16_t)image->data[i]);
i++;
for (uint16_t p = 0; p < count; p++)
{
if(image->data[i] == transparent_color)
LCDDriver_SendData(bg_color);
else
LCDDriver_SendData(image->data[i]);
decoded++;
i++;
if (pixels <= decoded)
return;
}
}
else //repeats
{
uint16_t count = ((int16_t)image->data[i]);
i++;
for (uint16_t p = 0; p < count; p++)
{
if(image->data[i] == transparent_color)
LCDDriver_SendData(bg_color);
else
LCDDriver_SendData(image->data[i]);
decoded++;
if (pixels <= decoded)
return;
}
i++;
}
}
}
static uint32_t RLEStream_pixels = 0;
static uint32_t RLEStream_decoded = 0;
static uint8_t RLEStream_state = 0;
void LCDDriver_printImage_RLECompressed_StartStream(uint16_t x, uint16_t y, uint16_t width, uint16_t height)
{
RLEStream_pixels = width * height;
RLEStream_decoded = 0;
RLEStream_state = 0;
LCDDriver_SetCursorAreaPosition(x, y, width + x - 1, height + y - 1);
}
void LCDDriver_printImage_RLECompressed_ContinueStream(int16_t *data, uint16_t len)
{
static uint16_t nr_count = 0;
static uint16_t nr_count_p = 0;
static uint16_t r_count = 0;
static uint16_t r_count_p = 0;
uint32_t processed = 0;
while (processed < len)
{
if ((((int16_t)data[processed] < 0) && (RLEStream_state == 0)) || (RLEStream_state == 1)) // no repeats
{
if(RLEStream_state == 0)
{
nr_count = (-(int16_t)data[processed]);
nr_count_p = 0;
processed++;
}
RLEStream_state = 1;
if(processed >= len)
return;
for (; nr_count_p < nr_count;)
{
LCDDriver_SendData(data[processed]);
RLEStream_decoded++;
nr_count_p++;
processed++;
if (RLEStream_pixels <= RLEStream_decoded)
return;
if(processed >= len && nr_count_p < nr_count)
return;
}
RLEStream_state = 0;
}
else if ((((int16_t)data[processed] > 0) && (RLEStream_state == 0)) || (RLEStream_state == 2)) //repeats
{
if(RLEStream_state == 0)
{
r_count = ((int16_t)data[processed]);
r_count_p = 0;
processed++;
}
RLEStream_state = 2;
if(processed >= len)
return;
for (; r_count_p < r_count;)
{
LCDDriver_SendData(data[processed]);
r_count_p++;
RLEStream_decoded++;
if (RLEStream_pixels <= RLEStream_decoded)
return;
}
processed++;
RLEStream_state = 0;
}
else
processed++;
}
}
inline uint16_t addColor(uint16_t color, uint8_t add_r, uint8_t add_g, uint8_t add_b)
{
uint8_t r = ((color >> 11) & 0x1F) + add_r;
uint8_t g = ((color >> 5) & 0x3F) + (uint8_t)(add_g << 1);
uint8_t b = ((color >> 0) & 0x1F) + add_b;
if (r > 31)
r = 31;
if (g > 63)
g = 63;
if (b > 31)
b = 31;
return (uint16_t)((r << 11) | (g << 5) | b);
}
inline uint16_t mixColors(uint16_t color1, uint16_t color2, float32_t opacity)
{
uint8_t r = (uint8_t)((float32_t)((color1 >> 11) & 0x1F) * (1.0f - opacity) + (float32_t)((color2 >> 11) & 0x1F) * opacity);
uint8_t g = (uint8_t)((float32_t)((color1 >> 5) & 0x3F) * (1.0f - opacity) + (float32_t)((color2 >> 5) & 0x3F) * opacity);
uint8_t b = (uint8_t)((float32_t)((color1 >> 0) & 0x1F) * (1.0f - opacity) + (float32_t)((color2 >> 0) & 0x1F) * opacity);
if (r > 31)
r = 31;
if (g > 63)
g = 63;
if (b > 31)
b = 31;
return (uint16_t)(r << 11) | (uint16_t)(g << 5) | (uint16_t)b;
}