RLE for greyscale lcd (gives more firmware space!) (#1142)

* use RLE encodes bitmaps on 212x64 pixel radios

* fix model image display
fix icon display

* implement RLE bitmaps in companion for splash image on 212x64 radios
reserve 3kB for RLE bitmaps in firmware

* fix size check

* use defines instead of magic numbers

* fix display of splash screens on 212x64 radios

* add warning message if compressed image is larger than the reserved space
This commit is contained in:
Malte Langermann
2021-12-04 15:06:23 +11:00
committed by GitHub
parent 995e41469e
commit ec01fa8df9
12 changed files with 317 additions and 33 deletions
+1 -1
View File
@@ -6,5 +6,5 @@ set(STICKS_ARGS --rows 4)
add_bitmaps_target(taranis_xbm ${RADIO_SRC_DIR}/bitmaps/sticks.xbm 1bit "${STICKS_ARGS}") # 1bit format, 1byte size, split into 4 rows
add_fonts_target(taranis_fonts ${RADIO_SRC_DIR}/fonts/${FONT_DIR}/*.png)
add_bitmaps_target(taranis_bitmaps ${RADIO_SRC_DIR}/bitmaps/212x64/*.png 4bits "")
add_bitmaps_target(taranis_bitmaps ${RADIO_SRC_DIR}/bitmaps/212x64/*.png 4bits "--rle")
add_dependencies(taranis_bitmaps taranis_fonts taranis_xbm)
+5 -1
View File
@@ -204,6 +204,10 @@ bool loadModelBitmap(char * name, uint8_t * bitmap)
}
// In all error cases, we set the default logo
memcpy(bitmap, logo_taranis, MODEL_BITMAP_SIZE);
RleBitmap pic(logo_taranis, 0);
*bitmap++ = pic.getWidth();
*bitmap++ = pic.getRawRows();
for(int i=0; i < MODEL_BITMAP_SIZE-2; i++)
*bitmap++ = pic.getNext();
return false;
}
+35
View File
@@ -976,4 +976,39 @@ void lcdDrawBitmap(coord_t x, coord_t y, const uint8_t * img, coord_t offset, co
}
}
}
void lcdDrawRleBitmap(coord_t x, coord_t y, const uint8_t * img, coord_t offset, coord_t width)
{
RleBitmap pic(img, offset);
uint8_t w = pic.getWidth();
if (!width || width > w) {
width = w;
}
if (x+width > LCD_W) {
if (x >= LCD_W ) return;
width = LCD_W-x;
}
uint8_t rows = pic.getRows();
for (uint8_t row=0; row<rows; row++) {
uint8_t *p = &displayBuf[(row + (y/2)) * LCD_W + x];
for (coord_t i=0; i<width; i++) {
if (p >= DISPLAY_END) return;
uint8_t b = pic.getNext();
if (y & 1) {
*p = (*p & 0x0f) + ((b & 0x0f) << 4);
if ((p+LCD_W) < DISPLAY_END) {
*(p+LCD_W) = (*(p+LCD_W) & 0xf0) + ((b & 0xf0) >> 4);
}
}
else {
*p = b;
}
p++;
}
pic.goToNextRow();
pic.skip(offset);
}
}
#endif
+74 -1
View File
@@ -168,7 +168,9 @@ void drawTelemetryTopBar();
void lcdDraw1bitBitmap(coord_t x, coord_t y, const unsigned char * img, uint8_t idx, LcdFlags att=0);
void lcdDrawBitmap(coord_t x, coord_t y, const uint8_t * img, coord_t offset=0, coord_t width=0);
#define LCD_ICON(x, y, icon) lcdDrawBitmap(x, y, icons, icon)
void lcdDrawRleBitmap(coord_t x, coord_t y, const uint8_t * img, coord_t offset=0, coord_t width=0);
#define LCD_ICON(x, y, icon) lcdDrawRleBitmap(x, y, icons, icon)
void lcdClear();
@@ -193,4 +195,75 @@ inline pixel_t getPixel(unsigned int x, unsigned int y)
uint8_t getTextWidth(const char * s, uint8_t len=0, LcdFlags flags=0);
class RleBitmap
{
public:
RleBitmap(const uint8_t *src, coord_t offset) :
state(RLE_FIRST_BYTE), src(src), curPtr(src), byte(0), curCount(0), pos(0)
{
width = *curPtr++;
rawRows = *curPtr++;
rows = (rawRows +1)/2;
skip(offset);
}
void skip(coord_t count)
{
while(count)
{
count--;
getNext();
}
}
uint8_t getNext()
{
pos++;
switch(state)
{
case RLE_FIRST_BYTE:
byte = *curPtr++;
if(byte == *curPtr)
state = RLE_SECOND_BYTE;
break;
case RLE_SECOND_BYTE:
byte = *curPtr++;
curCount = (*curPtr++)+1;
state = RLE_CONTINUE;
// fall through
case RLE_CONTINUE:
curCount--;
if(!curCount)
state = RLE_FIRST_BYTE;
break;
}
return byte;
}
uint8_t getWidth() const { return width; }
uint8_t getRows() const { return rows; }
uint8_t getRawRows() const { return rawRows; }
void goToNextRow()
{
coord_t offset = pos%width;
if(offset)
skip(width - pos%width);
}
private:
enum State {RLE_FIRST_BYTE, RLE_SECOND_BYTE, RLE_CONTINUE} state;
const uint8_t* src;
const uint8_t* curPtr;
uint8_t width;
uint8_t rows;
uint8_t rawRows;
uint8_t byte;
uint16_t curCount;
coord_t pos;
};
#endif // _LCD_H_
+1 -1
View File
@@ -28,7 +28,7 @@ const unsigned char ASTERISK_BITMAP[] = {
void drawAlertBox(const char * title, const char * text, const char * action)
{
lcdClear();
lcdDrawBitmap(0, 0, ASTERISK_BITMAP);
lcdDrawRleBitmap(0, 0, ASTERISK_BITMAP);
#define MESSAGE_LCD_OFFSET 60
+11 -6
View File
@@ -22,16 +22,21 @@
#include "opentx.h"
#if defined(SPLASH)
const unsigned char splashdata[] = {
'S','P','S',0,
#include "bitmaps/212x64/splash.lbm"
'S','P','E',0 };
const unsigned char * const splash_lbm = splashdata+4;
#define MAXIMUM_SPLASH_IMAGE_SIZE 3072
struct {
const uint8_t __magic_prefix[4] = { 'S','P','S',0 };
const uint8_t splashdata[MAXIMUM_SPLASH_IMAGE_SIZE] = {
#include "bitmaps/212x64/splash.lbm"
};
const uint8_t __magic_suffix[4] = { 'S','P','E',0 };
} splash_struct;
static_assert(sizeof(splash_struct.splashdata) <= MAXIMUM_SPLASH_IMAGE_SIZE, "");
const unsigned char * const splash_lbm = splash_struct.splashdata;
void drawSplash()
{
lcdClear();
lcdDrawBitmap(0, 0, splash_lbm);
lcdDrawRleBitmap(0, 0, splash_lbm);
#if MENUS_LOCK == 1
if (readonly == false) {
+4 -4
View File
@@ -52,9 +52,9 @@ void drawStartupAnimation(uint32_t duration, uint32_t totalDuration)
lcdClear();
if (index == 0)
lcdDrawBitmap((LCD_W - ANIMATIONS_BITMAP_WIDTH) / 2, (LCD_H - ANIMATIONS_BITMAP_HEIGHT) / 2, bmp_lock, 0, ANIMATIONS_BITMAP_WIDTH);
lcdDrawRleBitmap((LCD_W - ANIMATIONS_BITMAP_WIDTH) / 2, (LCD_H - ANIMATIONS_BITMAP_HEIGHT) / 2, bmp_lock, 0, ANIMATIONS_BITMAP_WIDTH);
else
lcdDrawBitmap((LCD_W - ANIMATIONS_BITMAP_WIDTH) / 2, (LCD_H - ANIMATIONS_BITMAP_HEIGHT) / 2, bmp_startup, (index - 1) * ANIMATIONS_BITMAP_WIDTH, ANIMATIONS_BITMAP_WIDTH);
lcdDrawRleBitmap((LCD_W - ANIMATIONS_BITMAP_WIDTH) / 2, (LCD_H - ANIMATIONS_BITMAP_HEIGHT) / 2, bmp_startup, (index - 1) * ANIMATIONS_BITMAP_WIDTH, ANIMATIONS_BITMAP_WIDTH);
lcdRefresh();
}
@@ -69,7 +69,7 @@ void drawShutdownAnimation(uint32_t duration, uint32_t totalDuration, const char
lcdRefreshWait();
lcdClear();
lcdDrawBitmap((LCD_W - ANIMATIONS_BITMAP_WIDTH) / 2, (LCD_H - ANIMATIONS_BITMAP_HEIGHT) / 2, bmp_shutdown, (3 - index) * ANIMATIONS_BITMAP_WIDTH, ANIMATIONS_BITMAP_WIDTH);
lcdDrawRleBitmap((LCD_W - ANIMATIONS_BITMAP_WIDTH) / 2, (LCD_H - ANIMATIONS_BITMAP_HEIGHT) / 2, bmp_shutdown, (3 - index) * ANIMATIONS_BITMAP_WIDTH, ANIMATIONS_BITMAP_WIDTH);
if (message) {
lcdDrawText((LCD_W - getTextWidth(message)) / 2, LCD_H - 2*FH, message);
}
@@ -81,7 +81,7 @@ void drawSleepBitmap()
{
lcdRefreshWait();
lcdClear();
lcdDrawBitmap((LCD_W - ANIMATIONS_BITMAP_WIDTH) / 2, (LCD_H - ANIMATIONS_BITMAP_HEIGHT) / 2, bmp_sleep, 0);
lcdDrawRleBitmap((LCD_W - ANIMATIONS_BITMAP_WIDTH) / 2, (LCD_H - ANIMATIONS_BITMAP_HEIGHT) / 2, bmp_sleep, 0);
lcdRefresh();
lcdRefreshWait();
}
+1 -1
View File
@@ -203,7 +203,7 @@ void displayTopBarGauge(coord_t x, int count, bool blinking=false)
}
#define LCD_NOTIF_ICON(x, icon) \
lcdDrawBitmap(x, BAR_Y, icons, icon); \
lcdDrawRleBitmap(x, BAR_Y, icons, icon); \
lcdDrawSolidHorizontalLine(x, BAR_Y+8, 11)
void displayTopBar()